diff options
Diffstat (limited to 'qemu/roms/u-boot/tools')
167 files changed, 26561 insertions, 0 deletions
diff --git a/qemu/roms/u-boot/tools/.gitignore b/qemu/roms/u-boot/tools/.gitignore new file mode 100644 index 000000000..b1e997fc3 --- /dev/null +++ b/qemu/roms/u-boot/tools/.gitignore @@ -0,0 +1,22 @@ +/bmp_logo +/envcrc +/fit_check_sign +/fit_info +/gen_eth_addr +/img2srec +/kwboot +/dumpimage +/mkenvimage +/mkimage +/mkexynosspl +/mpc86x_clk +/mxsboot +/ncb +/proftool +/relocate-rela +/ubsha1 +/xway-swap-bytes +/*.exe +/easylogo/easylogo +/gdb/gdbcont +/gdb/gdbsend diff --git a/qemu/roms/u-boot/tools/Makefile b/qemu/roms/u-boot/tools/Makefile new file mode 100644 index 000000000..6e43a0150 --- /dev/null +++ b/qemu/roms/u-boot/tools/Makefile @@ -0,0 +1,217 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +# +# toolchains targeting win32 generate .exe files +# +ifneq (,$(findstring WIN32 ,$(shell $(HOSTCC) -E -dM -xc /dev/null))) +SFX = .exe +else +SFX = +endif + +# Enable all the config-independent tools +ifneq ($(HOST_TOOLS_ALL),) +CONFIG_LCD_LOGO = y +CONFIG_CMD_LOADS = y +CONFIG_CMD_NET = y +CONFIG_XWAY_SWAP_BYTES = y +CONFIG_NETCONSOLE = y +CONFIG_SHA1_CHECK_UB_IMG = y +endif + +subdir-$(HOST_TOOLS_ALL) += easylogo +subdir-$(HOST_TOOLS_ALL) += gdb + +# Merge all the different vars for envcrc into one +ENVCRC-$(CONFIG_ENV_IS_EMBEDDED) = y +ENVCRC-$(CONFIG_ENV_IS_IN_DATAFLASH) = y +ENVCRC-$(CONFIG_ENV_IS_IN_EEPROM) = y +ENVCRC-$(CONFIG_ENV_IS_IN_FLASH) = y +ENVCRC-$(CONFIG_ENV_IS_IN_ONENAND) = y +ENVCRC-$(CONFIG_ENV_IS_IN_NAND) = y +ENVCRC-$(CONFIG_ENV_IS_IN_NVRAM) = y +ENVCRC-$(CONFIG_ENV_IS_IN_SPI_FLASH) = y +CONFIG_BUILD_ENVCRC ?= $(ENVCRC-y) + +# TODO: CONFIG_CMD_LICENSE does not work +hostprogs-$(CONFIG_CMD_LICENSE) += bin2header$(SFX) +hostprogs-$(CONFIG_LCD_LOGO) += bmp_logo$(SFX) +hostprogs-$(CONFIG_VIDEO_LOGO) += bmp_logo$(SFX) +HOSTCFLAGS_bmp_logo$(SFX).o := -pedantic + +hostprogs-$(CONFIG_BUILD_ENVCRC) += envcrc$(SFX) +envcrc$(SFX)-objs := crc32.o env_embedded.o envcrc.o sha1.o + +hostprogs-$(CONFIG_CMD_NET) += gen_eth_addr$(SFX) +HOSTCFLAGS_gen_eth_addr$(SFX).o := -pedantic + +hostprogs-$(CONFIG_CMD_LOADS) += img2srec$(SFX) +HOSTCFLAGS_img2srec$(SFX).o := -pedantic + +hostprogs-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX) +HOSTCFLAGS_xway-swap-bytes$(SFX).o := -pedantic + +hostprogs-y += mkenvimage$(SFX) +mkenvimage$(SFX)-objs := crc32.o mkenvimage.o os_support.o + +hostprogs-y += dumpimage$(SFX) mkimage$(SFX) +hostprogs-$(CONFIG_FIT_SIGNATURE) += fit_info$(SFX) fit_check_sign$(SFX) + +FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := image-sig.o +# Flattened device tree objects +LIBFDT_OBJS := fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o +RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := rsa-sign.o rsa-verify.o rsa-checksum.o + +# common objs for dumpimage and mkimage +dumpimage-mkimage-objs := aisimage.o \ + $(FIT_SIG_OBJS-y) \ + crc32.o \ + default_image.o \ + fdtdec.o \ + fit_common.o \ + fit_image.o \ + gpimage.o \ + gpimage-common.o \ + image-fit.o \ + image-host.o \ + image.o \ + imagetool.o \ + imximage.o \ + kwbimage.o \ + md5.o \ + mxsimage.o \ + omapimage.o \ + os_support.o \ + pblimage.o \ + sha1.o \ + sha256.o \ + ublimage.o \ + $(LIBFDT_OBJS) \ + $(RSA_OBJS-y) + +dumpimage$(SFX)-objs := $(dumpimage-mkimage-objs) dumpimage.o +mkimage$(SFX)-objs := $(dumpimage-mkimage-objs) mkimage.o +fit_info$(SFX)-objs := $(dumpimage-mkimage-objs) fit_info.o +fit_check_sign$(SFX)-objs := $(dumpimage-mkimage-objs) fit_check_sign.o + +# TODO(sjg@chromium.org): Is this correct on Mac OS? + +# MXSImage needs LibSSL +ifneq ($(CONFIG_MX23)$(CONFIG_MX28),) +HOSTLOADLIBES_dumpimage$(SFX) := -lssl -lcrypto +HOSTLOADLIBES_mkimage$(SFX) := -lssl -lcrypto +HOSTLOADLIBES_fit_info$(SFX) := -lssl -lcrypto +HOSTLOADLIBES_fit_check_sign$(SFX) := -lssl -lcrypto +# Add CONFIG_MXS into host CFLAGS, so we can check whether or not register +# the mxsimage support within tools/mxsimage.c . +HOSTCFLAGS_mxsimage.o += -DCONFIG_MXS +endif + +ifdef CONFIG_FIT_SIGNATURE +HOSTLOADLIBES_dumpimage$(SFX) := -lssl -lcrypto +HOSTLOADLIBES_mkimage$(SFX) := -lssl -lcrypto +HOSTLOADLIBES_fit_info$(SFX) := -lssl -lcrypto +HOSTLOADLIBES_fit_check_sign$(SFX) := -lssl -lcrypto + +# This affects include/image.h, but including the board config file +# is tricky, so manually define this options here. +HOST_EXTRACFLAGS += -DCONFIG_FIT_SIGNATURE +endif + +hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl$(SFX) +hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl$(SFX) +HOSTCFLAGS_mkexynosspl$(SFX).o := -pedantic + +hostprogs-$(CONFIG_MX23) += mxsboot$(SFX) +hostprogs-$(CONFIG_MX28) += mxsboot$(SFX) +HOSTCFLAGS_mxsboot$(SFX).o := -pedantic + +hostprogs-$(CONFIG_NETCONSOLE) += ncb$(SFX) +hostprogs-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX) + +ubsha1$(SFX)-objs := os_support.o sha1.o ubsha1.o + +HOSTCFLAGS_ubsha1.o := -pedantic + +hostprogs-$(CONFIG_KIRKWOOD) += kwboot$(SFX) +hostprogs-y += proftool$(SFX) +hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela$(SFX) + +# We build some files with extra pedantic flags to try to minimize things +# that won't build on some weird host compiler -- though there are lots of +# exceptions for files that aren't complaint. +HOSTCFLAGS_crc32.o := -pedantic +HOSTCFLAGS_md5.o := -pedantic +HOSTCFLAGS_sha1.o := -pedantic +HOSTCFLAGS_sha256.o := -pedantic + +# Don't build by default +#hostprogs-$(CONFIG_PPC) += mpc86x_clk$(SFX) +#HOSTCFLAGS_mpc86x_clk$(SFX).o := -pedantic + +always := $(hostprogs-y) + +# Generated LCD/video logo +LOGO_H = $(objtree)/include/bmp_logo.h +LOGO_DATA_H = $(objtree)/include/bmp_logo_data.h +LOGO-$(CONFIG_LCD_LOGO) += $(LOGO_H) +LOGO-$(CONFIG_LCD_LOGO) += $(LOGO_DATA_H) +LOGO-$(CONFIG_VIDEO_LOGO) += $(LOGO_H) +LOGO-$(CONFIG_VIDEO_LOGO) += $(LOGO_DATA_H) + +# Generic logo +ifeq ($(LOGO_BMP),) +LOGO_BMP= $(srctree)/$(src)/logos/denx.bmp + +# Use board logo and fallback to vendor +ifneq ($(wildcard $(srctree)/$(src)/logos/$(BOARD).bmp),) +LOGO_BMP= $(srctree)/$(src)/logos/$(BOARD).bmp +else +ifneq ($(wildcard $(srctree)/$(src)/logos/$(VENDOR).bmp),) +LOGO_BMP= $(srctree)/$(src)/logos/$(VENDOR).bmp +endif +endif + +endif # !LOGO_BMP + +# +# Use native tools and options +# Define __KERNEL_STRICT_NAMES to prevent typedef overlaps +# Define _GNU_SOURCE to obtain the getline prototype from stdio.h +# +HOST_EXTRACFLAGS += -include $(srctree)/include/libfdt_env.h \ + $(patsubst -I%,-idirafter%, $(UBOOTINCLUDE)) \ + -I$(srctree)/lib/libfdt \ + -I$(srctree)/tools \ + -DCONFIG_SYS_TEXT_BASE=$(CONFIG_SYS_TEXT_BASE) \ + -DUSE_HOSTCC \ + -D__KERNEL_STRICT_NAMES \ + -D_GNU_SOURCE + +__build: $(LOGO-y) + +$(LOGO_H): $(obj)/bmp_logo $(LOGO_BMP) + $(obj)/bmp_logo --gen-info $(LOGO_BMP) > $@ + +$(LOGO_DATA_H): $(obj)/bmp_logo $(LOGO_BMP) + $(obj)/bmp_logo --gen-data $(LOGO_BMP) > $@ + +# Let clean descend into subdirs +subdir- += env + +ifneq ($(CROSS_BUILD_TOOLS),) +HOSTCC = $(CC) + +quiet_cmd_crosstools_strip = STRIP $^ + cmd_crosstools_strip = $(STRIP) $^; touch $@ +$(obj)/.strip: $(call objectify,$(filter $(always),$(hostprogs-y))) + $(call cmd,crosstools_strip) + +always += .strip +endif +clean-files += .strip diff --git a/qemu/roms/u-boot/tools/aisimage.c b/qemu/roms/u-boot/tools/aisimage.c new file mode 100644 index 000000000..8de370a2e --- /dev/null +++ b/qemu/roms/u-boot/tools/aisimage.c @@ -0,0 +1,431 @@ +/* + * (C) Copyright 2011 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include "aisimage.h" +#include <image.h> + +#define IS_FNC_EXEC(c) (cmd_table[c].AIS_cmd == AIS_CMD_FNLOAD) +#define WORD_ALIGN0 4 +#define WORD_ALIGN(len) (((len)+WORD_ALIGN0-1) & ~(WORD_ALIGN0-1)) +#define MAX_CMD_BUFFER 4096 + +static uint32_t ais_img_size; + +/* + * Supported commands for configuration file + */ +static table_entry_t aisimage_cmds[] = { + {CMD_DATA, "DATA", "Reg Write Data"}, + {CMD_FILL, "FILL", "Fill range with pattern"}, + {CMD_CRCON, "CRCON", "CRC Enable"}, + {CMD_CRCOFF, "CRCOFF", "CRC Disable"}, + {CMD_CRCCHECK, "CRCCHECK", "CRC Validate"}, + {CMD_JMPCLOSE, "JMPCLOSE", "Jump & Close"}, + {CMD_JMP, "JMP", "Jump"}, + {CMD_SEQREAD, "SEQREAD", "Sequential read"}, + {CMD_PLL0, "PLL0", "PLL0"}, + {CMD_PLL1, "PLL1", "PLL1"}, + {CMD_CLK, "CLK", "Clock configuration"}, + {CMD_DDR2, "DDR2", "DDR2 Configuration"}, + {CMD_EMIFA, "EMIFA", "EMIFA"}, + {CMD_EMIFA_ASYNC, "EMIFA_ASYNC", "EMIFA Async"}, + {CMD_PLL, "PLL", "PLL & Clock configuration"}, + {CMD_PSC, "PSC", "PSC setup"}, + {CMD_PINMUX, "PINMUX", "Pinmux setup"}, + {CMD_BOOTTABLE, "BOOT_TABLE", "Boot table command"}, + {-1, "", ""}, +}; + +static struct ais_func_exec { + uint32_t index; + uint32_t argcnt; +} ais_func_table[] = { + [CMD_PLL0] = {0, 2}, + [CMD_PLL1] = {1, 2}, + [CMD_CLK] = {2, 1}, + [CMD_DDR2] = {3, 8}, + [CMD_EMIFA] = {4, 5}, + [CMD_EMIFA_ASYNC] = {5, 5}, + [CMD_PLL] = {6, 3}, + [CMD_PSC] = {7, 1}, + [CMD_PINMUX] = {8, 3} +}; + +static struct cmd_table_t { + uint32_t nargs; + uint32_t AIS_cmd; +} cmd_table[] = { + [CMD_FILL] = { 4, AIS_CMD_FILL}, + [CMD_CRCON] = { 0, AIS_CMD_ENCRC}, + [CMD_CRCOFF] = { 0, AIS_CMD_DISCRC}, + [CMD_CRCCHECK] = { 2, AIS_CMD_ENCRC}, + [CMD_JMPCLOSE] = { 1, AIS_CMD_JMPCLOSE}, + [CMD_JMP] = { 1, AIS_CMD_JMP}, + [CMD_SEQREAD] = { 0, AIS_CMD_SEQREAD}, + [CMD_PLL0] = { 2, AIS_CMD_FNLOAD}, + [CMD_PLL1] = { 2, AIS_CMD_FNLOAD}, + [CMD_CLK] = { 1, AIS_CMD_FNLOAD}, + [CMD_DDR2] = { 8, AIS_CMD_FNLOAD}, + [CMD_EMIFA] = { 5, AIS_CMD_FNLOAD}, + [CMD_EMIFA_ASYNC] = { 5, AIS_CMD_FNLOAD}, + [CMD_PLL] = { 3, AIS_CMD_FNLOAD}, + [CMD_PSC] = { 1, AIS_CMD_FNLOAD}, + [CMD_PINMUX] = { 3, AIS_CMD_FNLOAD}, + [CMD_BOOTTABLE] = { 4, AIS_CMD_BOOTTBL}, +}; + +static uint32_t get_cfg_value(char *token, char *name, int linenr) +{ + char *endptr; + uint32_t value; + + errno = 0; + value = strtoul(token, &endptr, 16); + if (errno || (token == endptr)) { + fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", + name, linenr, token); + exit(EXIT_FAILURE); + } + return value; +} + +static int get_ais_table_id(uint32_t *ptr) +{ + + int i; + int func_no; + + for (i = 0; i < ARRAY_SIZE(cmd_table); i++) { + if (*ptr == cmd_table[i].AIS_cmd) { + if (cmd_table[i].AIS_cmd != AIS_CMD_FNLOAD) + return i; + + func_no = ((struct ais_cmd_func *)ptr)->func_args + & 0xFFFF; + if (func_no == ais_func_table[i].index) + return i; + } + } + + return -1; +} + +static void aisimage_print_header(const void *hdr) +{ + struct ais_header *ais_hdr = (struct ais_header *)hdr; + uint32_t *ptr; + struct ais_cmd_load *ais_load; + int id; + + if (ais_hdr->magic != AIS_MAGIC_WORD) { + fprintf(stderr, "Error: - AIS Magic Number not found\n"); + return; + } + fprintf(stdout, "Image Type: TI Davinci AIS Boot Image\n"); + fprintf(stdout, "AIS magic : %08x\n", ais_hdr->magic); + ptr = (uint32_t *)&ais_hdr->magic; + ptr++; + + while (*ptr != AIS_CMD_JMPCLOSE) { + /* Check if we find the image */ + if (*ptr == AIS_CMD_LOAD) { + ais_load = (struct ais_cmd_load *)ptr; + fprintf(stdout, "Image at : 0x%08x size 0x%08x\n", + ais_load->addr, + ais_load->size); + ptr = ais_load->data + ais_load->size / sizeof(*ptr); + continue; + } + + id = get_ais_table_id(ptr); + if (id < 0) { + fprintf(stderr, "Error: - AIS Image corrupted\n"); + return; + } + fprintf(stdout, "AIS cmd : %s\n", + get_table_entry_name(aisimage_cmds, NULL, id)); + ptr += cmd_table[id].nargs + IS_FNC_EXEC(id) + 1; + if (((void *)ptr - hdr) > ais_img_size) { + fprintf(stderr, + "AIS Image not terminated by JMPCLOSE\n"); + return; + } + } +} + +static uint32_t *ais_insert_cmd_header(uint32_t cmd, uint32_t nargs, + uint32_t *parms, struct image_type_params *tparams, + uint32_t *ptr) +{ + int i; + + *ptr++ = cmd_table[cmd].AIS_cmd; + if (IS_FNC_EXEC(cmd)) + *ptr++ = ((nargs & 0xFFFF) << 16) + ais_func_table[cmd].index; + + /* Copy parameters */ + for (i = 0; i < nargs; i++) + *ptr++ = cpu_to_le32(parms[i]); + + return ptr; + +} + +static uint32_t *ais_alloc_buffer(struct image_tool_params *params) +{ + int dfd; + struct stat sbuf; + char *datafile = params->datafile; + uint32_t *ptr; + + dfd = open(datafile, O_RDONLY|O_BINARY); + if (dfd < 0) { + fprintf(stderr, "%s: Can't open %s: %s\n", + params->cmdname, datafile, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (fstat(dfd, &sbuf) < 0) { + fprintf(stderr, "%s: Can't stat %s: %s\n", + params->cmdname, datafile, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* + * Place for header is allocated. The size is taken from + * the size of the datafile, that the ais_image_generate() + * will copy into the header. Copying the datafile + * is not left to the main program, because after the datafile + * the header must be terminated with the Jump & Close command. + */ + ais_img_size = WORD_ALIGN(sbuf.st_size) + MAX_CMD_BUFFER; + ptr = (uint32_t *)malloc(WORD_ALIGN(sbuf.st_size) + MAX_CMD_BUFFER); + if (!ptr) { + fprintf(stderr, "%s: malloc return failure: %s\n", + params->cmdname, strerror(errno)); + exit(EXIT_FAILURE); + } + + close(dfd); + + return ptr; +} + +static uint32_t *ais_copy_image(struct image_tool_params *params, + uint32_t *aisptr) + +{ + int dfd; + struct stat sbuf; + char *datafile = params->datafile; + void *ptr; + + dfd = open(datafile, O_RDONLY|O_BINARY); + if (dfd < 0) { + fprintf(stderr, "%s: Can't open %s: %s\n", + params->cmdname, datafile, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (fstat(dfd, &sbuf) < 0) { + fprintf(stderr, "%s: Can't stat %s: %s\n", + params->cmdname, datafile, strerror(errno)); + exit(EXIT_FAILURE); + } + + ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); + *aisptr++ = AIS_CMD_LOAD; + *aisptr++ = params->ep; + *aisptr++ = sbuf.st_size; + memcpy((void *)aisptr, ptr, sbuf.st_size); + aisptr += WORD_ALIGN(sbuf.st_size) / sizeof(uint32_t); + + (void) munmap((void *)ptr, sbuf.st_size); + (void) close(dfd); + + return aisptr; + +} + +static int aisimage_generate(struct image_tool_params *params, + struct image_type_params *tparams) +{ + FILE *fd = NULL; + char *line = NULL; + char *token, *saveptr1, *saveptr2; + int lineno = 0; + int fld; + size_t len; + int32_t cmd; + uint32_t nargs, cmd_parms[10]; + uint32_t value, size; + char *name = params->imagename; + uint32_t *aishdr; + + fd = fopen(name, "r"); + if (fd == 0) { + fprintf(stderr, + "Error: %s - Can't open AIS configuration\n", name); + exit(EXIT_FAILURE); + } + + /* + * the size of the header is variable and is computed + * scanning the configuration file. + */ + tparams->header_size = 0; + + /* + * Start allocating a buffer suitable for most command + * The buffer is then reallocated if it is too small + */ + aishdr = ais_alloc_buffer(params); + tparams->hdr = aishdr; + *aishdr++ = AIS_MAGIC_WORD; + + /* Very simple parsing, line starting with # are comments + * and are dropped + */ + while ((getline(&line, &len, fd)) > 0) { + lineno++; + + token = strtok_r(line, "\r\n", &saveptr1); + if (token == NULL) + continue; + + /* Check inside the single line */ + line = token; + fld = CFG_COMMAND; + cmd = CMD_INVALID; + nargs = 0; + while (token != NULL) { + token = strtok_r(line, " \t", &saveptr2); + if (token == NULL) + break; + + /* Drop all text starting with '#' as comments */ + if (token[0] == '#') + break; + + switch (fld) { + case CFG_COMMAND: + cmd = get_table_entry_id(aisimage_cmds, + "aisimage commands", token); + if (cmd < 0) { + fprintf(stderr, + "Error: %s[%d] - Invalid command" + "(%s)\n", name, lineno, token); + + exit(EXIT_FAILURE); + } + break; + case CFG_VALUE: + value = get_cfg_value(token, name, lineno); + cmd_parms[nargs++] = value; + if (nargs > cmd_table[cmd].nargs) { + fprintf(stderr, + "Error: %s[%d] - too much arguments:" + "(%s) for command %s\n", name, + lineno, token, + aisimage_cmds[cmd].sname); + exit(EXIT_FAILURE); + } + break; + } + line = NULL; + fld = CFG_VALUE; + } + if (cmd != CMD_INVALID) { + /* Now insert the command into the header */ + aishdr = ais_insert_cmd_header(cmd, nargs, cmd_parms, + tparams, aishdr); + } + + } + fclose(fd); + + aishdr = ais_copy_image(params, aishdr); + + /* Add Jmp & Close */ + *aishdr++ = AIS_CMD_JMPCLOSE; + *aishdr++ = params->ep; + + size = (aishdr - (uint32_t *)tparams->hdr) * sizeof(uint32_t); + tparams->header_size = size; + + return 0; +} + +static int aisimage_check_image_types(uint8_t type) +{ + if (type == IH_TYPE_AISIMAGE) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +} + +static int aisimage_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + struct ais_header *ais_hdr = (struct ais_header *)ptr; + + if (ais_hdr->magic != AIS_MAGIC_WORD) + return -FDT_ERR_BADSTRUCTURE; + + /* Store the total size to remember in print_hdr */ + ais_img_size = image_size; + + return 0; +} + +static void aisimage_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ +} + +int aisimage_check_params(struct image_tool_params *params) +{ + if (!params) + return CFG_INVALID; + if (!strlen(params->imagename)) { + fprintf(stderr, "Error: %s - Configuration file not specified, " + "it is needed for aisimage generation\n", + params->cmdname); + return CFG_INVALID; + } + /* + * Check parameters: + * XIP is not allowed and verify that incompatible + * parameters are not sent at the same time + * For example, if list is required a data image must not be provided + */ + return (params->dflag && (params->fflag || params->lflag)) || + (params->fflag && (params->dflag || params->lflag)) || + (params->lflag && (params->dflag || params->fflag)) || + (params->xflag) || !(strlen(params->imagename)); +} + +/* + * aisimage parameters + */ +static struct image_type_params aisimage_params = { + .name = "TI Davinci AIS Boot Image support", + .header_size = 0, + .hdr = NULL, + .check_image_type = aisimage_check_image_types, + .verify_header = aisimage_verify_header, + .print_header = aisimage_print_header, + .set_header = aisimage_set_header, + .check_params = aisimage_check_params, + .vrec_header = aisimage_generate, +}; + +void init_ais_image_type(void) +{ + register_image_type(&aisimage_params); +} diff --git a/qemu/roms/u-boot/tools/aisimage.h b/qemu/roms/u-boot/tools/aisimage.h new file mode 100644 index 000000000..e1aa3ef70 --- /dev/null +++ b/qemu/roms/u-boot/tools/aisimage.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2011 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _AISIMAGE_H_ +#define _AISIMAGE_H_ + +/* all values are for little endian systems */ +#define AIS_MAGIC_WORD 0x41504954 +#define AIS_FCN_MAX 8 + +enum { + AIS_CMD_LOAD = 0x58535901, + AIS_CMD_VALCRC = 0x58535902, + AIS_CMD_ENCRC = 0x58535903, + AIS_CMD_DISCRC = 0x58535904, + AIS_CMD_JMP = 0x58535905, + AIS_CMD_JMPCLOSE = 0x58535906, + AIS_CMD_BOOTTBL = 0x58535907, + AIS_CMD_FILL = 0x5853590A, + AIS_CMD_FNLOAD = 0x5853590D, + AIS_CMD_SEQREAD = 0x58535963, +}; + +struct ais_cmd_load { + uint32_t cmd; + uint32_t addr; + uint32_t size; + uint32_t data[1]; +}; + +struct ais_cmd_func { + uint32_t cmd; + uint32_t func_args; + uint32_t parms[AIS_FCN_MAX]; +}; + +struct ais_cmd_jmpclose { + uint32_t cmd; + uint32_t addr; +}; + +#define CMD_DATA_STR "DATA" + +enum ais_file_cmd { + CMD_INVALID, + CMD_FILL, + CMD_CRCON, + CMD_CRCOFF, + CMD_CRCCHECK, + CMD_JMPCLOSE, + CMD_JMP, + CMD_SEQREAD, + CMD_DATA, + CMD_PLL0, + CMD_PLL1, + CMD_CLK, + CMD_DDR2, + CMD_EMIFA, + CMD_EMIFA_ASYNC, + CMD_PLL, + CMD_PSC, + CMD_PINMUX, + CMD_BOOTTABLE +}; + +enum aisimage_fld_types { + CFG_INVALID = -1, + CFG_COMMAND, + CFG_VALUE, +}; + +struct ais_header { + uint32_t magic; + char data[1]; +}; + +#endif /* _AISIMAGE_H_ */ diff --git a/qemu/roms/u-boot/tools/bddb/README b/qemu/roms/u-boot/tools/bddb/README new file mode 100644 index 000000000..9bee59a0f --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/README @@ -0,0 +1,116 @@ +Hymod Board Database + +(C) Copyright 2001 +Murray Jensen <Murray.Jensen@csiro.au> +CSIRO Manufacturing Science and Technology, Preston Lab + +25-Jun-01 + +This stuff is a set of PHP/MySQL scripts to implement a custom board +database. It will need *extensive* hacking to modify it to keep the +information about your custom boards that you want, however it is a good +starting point. + +How it is used: + + 1. a board has gone through all the hardware testing etc and is + ready to have the flash programmed for the first time - first you + go to a web page and fill in information about the board in a form + to register it in a database + + 2. the web stuff allocates a (unique) serial number and (optionally) + a (locally administered) ethernet address and stores the information + in a database using the serial number as the key (can do whole + batches of boards in one go and/or use a previously registered board + as defaults for the new board(s)) + + 3. it then creates a file in the tftp area of a server somewhere + containing the board information in a simple text format (one + per serial number) + + 4. all hymod boards have an i2c eeprom, and when U-Boot sees that + the eeprom is unitialised, it prompts for a serial number and + ethernet address (if not set), then transfers the file created + in step 3 from the server and initialises the eeprom from its + contents + +What this means is you can't boot the board until you have allocated a serial +number, but you don't have to type it all twice - you do it once on the web +and the board then finds the info it needs to initialise its eeprom. The +other side of the coin is the reading of the eeprom and how it gets passed +to Linux (or another O/S). + +To see how this is all done for the hymod boards look at the code in the +"board/hymod" directory and in the file "include/asm/hymod.h". Hymod boards +can have a mezzanine card which also have an eeprom that needs allocating, +the same process is used for these as well - just a different i2c address. + +Other forms provide the following functions: + + - browsing the board database + - editing board information (one at a time) + - maintaining/browsing a (simple) per board event log + +You will need: MySQL (I use version 3.23.7-alpha), PHP4 (with MySQL +support enabled) and a web server (I use Apache 1.3.x). + +I originally started by using phpMyBuilder (http://kyber.dk/phpMyBuilder) +but it soon got far more complicated than that could handle (but I left +the copyright messages in there anyway). Most of the code resides in the +common defs.php file, which shouldn't need much alteration - all the work +will be in shaping the front-end php files to your liking. + +Here's a quick summary of what needs doing to use it for your boards: + +1. get phpMyAdmin (http://phpwizard.net/projects/phpMyAdmin/) - it's an + invaluable tool for this sort of stuff (this step is optional of course) + +2. edit "bddb.css" to your taste, if you could be bothered - I have no + idea what is in there or what it does - I copied it from somewhere else + ("user.css" from the phpMyEdit (http://phpmyedit.sourcerforge.net) package, + I think) - I figure one day I'll see what sort of things I can change + in there. + +3. create a mysql database - call it whatever you like + +4. edit "create_tables.sql" and modify the "boards" table schema to + reflect the information you want to keep about your boards. It may or + may not be easier to do this and the next step in phpMyAdmin. Check out + the MySQL documentation at http://www.mysql.com/doc/ in particular the + column types at http://www.mysql.com/doc/C/o/Column_types.html - Note + there is only support for a few data types: + + int - presented as an html text input + char/text - presented as an html text input + date - presented as an html text input + enum - presented as an html radio input + + I also have what I call "enum_multi" which is a set of enums with the + same name, but suffixed with a number e.g. fred0, fred1, fred2. These + are presented as a number of html select's with a single label "fred" + this is useful for board characteristics that have multiple items of + the same type e.g. multiple banks of sdram. + +5. use the "create_tables.sql" file to create the "boards" table in the + database e.g. mysql dbname < create_tables.sql + +6. create a user and password for the web server to log into the MySQL + database with; give this user select, insert and update privileges + to the database created in 3 (and delete, if you want the "delete" + functions in the edit forms to work- I have this turned off). phpMyAdmin + helps in this step. + +7. edit "config.php" and set the variables: $mysql_user, $mysql_pw, $mysql_db, + $bddb_cfgdir and $bddb_label - keep the contents of this file secret - it + contains the web servers username and password (the three $mysql_* vars + are set from the previous step) + +8. edit "defs.php" and a. adjust the various enum value arrays and b. edit + the function "pg_foot()" to remove my email address :-) + +9. do major hacking on the following files: browse.php, doedit.php, donew.php, + edit.php and new.php to reflect your database schema - fortunately the + hacking is fairly straight-forward, but it is boring and time-consuming. + +These notes were written rather hastily - if you find any obvious problems +please let me know. diff --git a/qemu/roms/u-boot/tools/bddb/badsubmit.php b/qemu/roms/u-boot/tools/bddb/badsubmit.php new file mode 100644 index 000000000..5092a3196 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/badsubmit.php @@ -0,0 +1,23 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + require("defs.php"); + pg_head("$bddb_label - Unknown Submit Type"); +?> +<center> + <font size="+4"> + <b> + The <?php echo "$bddb_label"; ?> form was submitted with an + unknown SUBMIT type <?php echo "(value was '$submit')" ?>. + <br></br> + Perhaps you typed the URL in directly? Click here to go to the + home page of the <a href="index.php"><?php echo "$bddb_label"; ?></a>. + </b> + </font> +</center> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/bddb.css b/qemu/roms/u-boot/tools/bddb/bddb.css new file mode 100644 index 000000000..dee2b2ee4 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/bddb.css @@ -0,0 +1,207 @@ +BODY { + background: #e0ffff; + color: #000000; + font-family: Arial, Verdana, Helvetica; +} +H1 { + font-family: "Copperplate Gothic Bold"; + background: transparent; + color: #993300; + text-align: center; +} +H2, H3, H4, H5 { + background: transparent; + color: #993300; + margin-top: 4%; + text-align: center; +} +Body.Plain Div.Abstract, Body.Plain P.Abstract { + background: #cccc99; + color: #333300; + border: white; + padding: 3%; + font-family: Times, Verdana; +} +TH.Nav { + background: #0000cc; + color: #ff9900; +} +TH.Menu { + background: #3366cc; + color: #ff9900; +} +A:hover { + color: #ff6600; +} +A.Menu:hover { + color: #ff6600; +} +A.HoMe:hover { + color: #ff6600; +} +A.Menu { + background: transparent; + color: #ffcc33; + font-family: Verdana, Helvetica, Arial; + font-size: smaller; + text-decoration: none; +} +A.Menu:visited { + background: transparent; + color: #ffcc99; +} +A.HoMe { + background: transparent; + color: #ffcc33; + font-family: Verdana, Helvetica, Arial; + text-decoration:none; +} +A.HoMe:visited { + background: transparent; + color: #ffcc99; +} +TH.Xmp { + background: #eeeeee; + color: #330066; + font-family: courier; + font-weight: normal; +} +TH.LuT { + background: #cccccc; + color: #000000; +} +TD.LuT { + background: #ffffcc; + color: #000000; + font-size: 85%; +} +TH.Info, TD.Info { + background: #ffffcc; + color: #660000; + font-family: "Comic Sans MS", Cursive, Verdana; + font-size: smaller; +} +Div.Info, P.Info { + background: #ffff99; + color: #990033; + text-align: left; + padding: 2%; + font-family: "Comic Sans MS", Cursive, Verdana; + font-size: 85%; + } +Div.Info A { + background: transparent; + color: #ff6600; +} +.HL { + background: #ffff99; + color: #000000; +} +TD.HL { + background: #ccffff; + color: #000000; +} +Div.Margins { + width: 512px; + text-align: center; +} +TD.Plain { + background: #ffffcc; + color: #000033; +} +.Type { + background: #cccccc; + color: #660000; +} +.Name { + background: #eeeeee; + color: #660000; + vertical-align: top; + text-align: right; +} +.Value { + background: #ffffee; + color: #000066; +} +.Drop { + background: #333366; + color: #ffcc33; + font-family: "Copperplate Gothic Light", Helvetica, Verdana, Arial; +} +A.Button:hover { + color: #ff6600; +} +A.Button { + text-decoration:none; + color: #003366; + background: #ffcc66; +} +.Button { + font-size: 9pt; + text-align: center; + text-decoration:none; + color: #003366; + background: #ffcc66; + margin-bottom: 2pt; + border-top: 2px solid #ffff99; + border-left: 2px solid #ffff99; + border-right: 2px solid #cc9933; + border-bottom: 2px solid #cc9933; + font-family: Verdana, Arial, "Comic Sans MS"; +} +.Banner { + width: 468; + font-size: 12pt; + text-align: center; + text-decoration:none; + color: #003366; + background: #ffcc66; + border-top: 4px solid #ffff99; + border-left: 4px solid #ffff99; + border-right: 4px solid #cc9933; + border-bottom: 4px solid #cc9933; + font-family: Verdana, Arial, "Comic Sans MS"; +} +TD.Nova, Body.Nova { + background: #000000; + font-family: "Times New Roman"; + font-weight: light; + color: #ffcc00; +} +Body.Nova A.Button { + background: gold; + color: #003366; +} +Body.Nova A.Banner { + background: transparent; + color: #003366; +} +Body.Nova A { + background: transparent; + text-decoration:none; + color: #ffd766; +} +Body.Nova H1, Body.Nova H2, Body.Nova H3, Body.Nova H4 { + background: transparent; + color: white; + margin-top: 4%; + text-align: center; + filter: Blur(Add=1, Direction=0, Strength=8); +} +Body.Nova Div.Abstract { + background: #000000; + color: #ffffff; + font-family: Times, Verdana; +} +Body.Nova A.Abstract { + background: transparent; + color: #ffeedd; +} +Body.Nova TH.LuT { + background: black; + color: #ffff99; +} +Body.Nova TD.LuT { + background: navy; + color: #ffff99; +} diff --git a/qemu/roms/u-boot/tools/bddb/brlog.php b/qemu/roms/u-boot/tools/bddb/brlog.php new file mode 100644 index 000000000..fccfbd011 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/brlog.php @@ -0,0 +1,109 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // list page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - Browse Board Log"); + + $serno=intval($serno); + if ($serno == 0) + die("serial number not specified or invalid!"); + + function print_cell($str) { + if ($str == '') + $str = ' '; + echo "\t<td>$str</td>\n"; + } +?> +<table align=center border=1 cellpadding=10> +<tr> +<th>serno / edit</th> +<th>ethaddr</th> +<th>date</th> +<th>batch</th> +<th>type</th> +<th>rev</th> +<th>location</th> +</tr> +<?php + $r=mysql_query("select * from boards where serno=$serno"); + + while($row=mysql_fetch_array($r)){ + foreach ($columns as $key) { + if (!key_in_array($key, $row)) + $row[$key] = ''; + } + + echo "<tr>\n"; + print_cell("<a href=\"edit.php?serno=$row[serno]\">$row[serno]</a>"); + print_cell($row['ethaddr']); + print_cell($row['date']); + print_cell($row['batch']); + print_cell($row['type']); + print_cell($row['rev']); + print_cell($row['location']); + echo "</tr>\n"; + } + + mysql_free_result($r); +?> +</table> +<hr></hr> +<p></p> +<?php + $limit=abs(isset($_REQUEST['limit'])?$_REQUEST['limit']:20); + $offset=abs(isset($_REQUEST['offset'])?$_REQUEST['offset']:0); + $lr=mysql_query("select count(*) as n from log where serno=$serno"); + $lrow=mysql_fetch_array($lr); + if($lrow['n']>$limit){ + $preoffset=max(0,$offset-$limit); + $postoffset=$offset+$limit; + echo "<table width=\"100%\">\n<tr align=center>\n"; + printf("<td><%sa href=\"%s?submit=Log&serno=$serno&offset=%d\"><img border=0 alt=\"<\" src=\"/icons/left.gif\"></a></td>\n", $offset>0?"":"no", $PHP_SELF, $preoffset); + printf("<td><%sa href=\"%s?submit=Log&serno=$serno&offset=%d\"><img border=0 alt=\">\" src=\"/icons/right.gif\"></a></td>\n", $postoffset<$lrow['n']?"":"no", $PHP_SELF, $postoffset); + echo "</tr>\n</table>\n"; + } + mysql_free_result($lr); +?> +<table width="100%" border=1 cellpadding=10> +<tr valign=top> +<th>logno / edit</th> +<th>date</th> +<th>who</th> +<th width="70%">details</th> +</tr> +<?php + $r=mysql_query("select * from log where serno=$serno order by logno limit $offset,$limit"); + + while($row=mysql_fetch_array($r)){ + echo "<tr>\n"; + print_cell("<a href=\"edlog.php?serno=$row[serno]&logno=$row[logno]\">$row[logno]</a>"); + print_cell($row['date']); + print_cell($row['who']); + print_cell("<pre>" . urldecode($row['details']) . "</pre>"); + echo "</tr>\n"; + } + + mysql_free_result($r); +?> +</table> +<hr></hr> +<p></p> +<table width="100%"> +<tr> + <td align=center> + <a href="newlog.php?serno=<?php echo "$serno"; ?>">Add to Log</a> + </td> + <td align=center> + <a href="index.php">Back to Start</a> + </td> +</tr> +</table> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/browse.php b/qemu/roms/u-boot/tools/bddb/browse.php new file mode 100644 index 000000000..675dfab74 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/browse.php @@ -0,0 +1,147 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // list page (hymod_bddb / boards) + + require("defs.php"); + + $serno=isset($_REQUEST['serno'])?$_REQUEST['serno']:''; + + $verbose=isset($_REQUEST['verbose'])?intval($_REQUEST['verbose']):0; + + pg_head("$bddb_label - Browse database" . ($verbose?" (verbose)":"")); +?> +<p></p> +<?php + $limit=isset($_REQUEST['limit'])?abs(intval($_REQUEST['limit'])):20; + $offset=isset($_REQUEST['offset'])?abs(intval($_REQUEST['offset'])):0; + + if ($serno == '') { + + $lr=mysql_query("select count(*) as n from boards"); + $lrow=mysql_fetch_array($lr); + + if($lrow['n']>$limit){ + $preoffset=max(0,$offset-$limit); + $postoffset=$offset+$limit; + echo "<table width=\"100%\">\n<tr>\n"; + printf("<td align=left><%sa href=\"%s?submit=Browse&offset=%d&verbose=%d\"><img border=0 alt=\"<\" src=\"/icons/left.gif\"></a></td>\n", $offset>0?"":"no", $PHP_SELF, $preoffset, $verbose); + printf("<td align=right><%sa href=\"%s?submit=Browse&offset=%d&verbose=%d\"><img border=0 alt=\">\" src=\"/icons/right.gif\"></a></td>\n", $postoffset<$lrow['n']?"":"no", $PHP_SELF, $postoffset, $offset); + echo "</tr>\n</table>\n"; + } + + mysql_free_result($lr); + } +?> +<table align=center border=1 cellpadding=10> +<tr> +<th></th> +<th>serno / edit</th> +<th>ethaddr</th> +<th>date</th> +<th>batch</th> +<th>type</th> +<th>rev</th> +<th>location</th> +<?php + if ($verbose) { + echo "<th>comments</th>\n"; + echo "<th>sdram</th>\n"; + echo "<th>flash</th>\n"; + echo "<th>zbt</th>\n"; + echo "<th>xlxtyp</th>\n"; + echo "<th>xlxspd</th>\n"; + echo "<th>xlxtmp</th>\n"; + echo "<th>xlxgrd</th>\n"; + echo "<th>cputyp</th>\n"; + echo "<th>cpuspd</th>\n"; + echo "<th>cpmspd</th>\n"; + echo "<th>busspd</th>\n"; + echo "<th>hstype</th>\n"; + echo "<th>hschin</th>\n"; + echo "<th>hschout</th>\n"; + } +?> +</tr> +<?php + $query = "select * from boards"; + if ($serno != '') { + $pre = " where "; + foreach (preg_split("/[\s,]+/", $serno) as $s) { + if (preg_match('/^[0-9]+$/',$s)) + $query .= $pre . "serno=" . $s; + else if (preg_match('/^([0-9]+)-([0-9]+)$/',$s,$m)) { + $m1 = intval($m[1]); $m2 = intval($m[2]); + if ($m2 <= $m1) + die("bad serial number range ($s)"); + $query .= $pre . "(serno>=$m[1] and serno<=$m[2])"; + } + else + die("illegal serial number ($s)"); + $pre = " or "; + } + } + $query .= " order by serno"; + if ($serno == '') + $query .= " limit $offset,$limit"; + + $r = mysql_query($query); + + function print_cell($str) { + if ($str == '') + $str = ' '; + echo "\t<td>$str</td>\n"; + } + + while($row=mysql_fetch_array($r)){ + foreach ($columns as $key) { + if (!key_in_array($key, $row)) + $row[$key] = ''; + } + + echo "<tr>\n"; + print_cell("<a href=\"brlog.php?serno=$row[serno]\">Log</a>"); + print_cell("<a href=\"edit.php?serno=$row[serno]\">$row[serno]</a>"); + print_cell($row['ethaddr']); + print_cell($row['date']); + print_cell($row['batch']); + print_cell($row['type']); + print_cell($row['rev']); + print_cell($row['location']); + if ($verbose) { + print_cell("<pre>\n" . urldecode($row['comments']) . + "\n\t</pre>"); + print_cell(gather_enum_multi_print("sdram", 4, $row)); + print_cell(gather_enum_multi_print("flash", 4, $row)); + print_cell(gather_enum_multi_print("zbt", 16, $row)); + print_cell(gather_enum_multi_print("xlxtyp", 4, $row)); + print_cell(gather_enum_multi_print("xlxspd", 4, $row)); + print_cell(gather_enum_multi_print("xlxtmp", 4, $row)); + print_cell(gather_enum_multi_print("xlxgrd", 4, $row)); + print_cell($row['cputyp']); + print_cell($row['cpuspd']); + print_cell($row['cpmspd']); + print_cell($row['busspd']); + print_cell($row['hstype']); + print_cell($row['hschin']); + print_cell($row['hschout']); + } + echo "</tr>\n"; + } +?> +</table> +<p></p> +<table width="100%"> +<tr> + <td align=center><?php + printf("<a href=\"%s?submit=Browse&offset=%d&verbose=%d%s\">%s Listing</a>\n", $PHP_SELF, $offset, $verbose?0:1, $serno!=''?"&serno=$serno":'', $verbose?"Terse":"Verbose"); + ?></td> + <td align=center><a href="index.php">Back to Start</a></td> +</tr> +</table> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/config.php b/qemu/roms/u-boot/tools/bddb/config.php new file mode 100644 index 000000000..67257578f --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/config.php @@ -0,0 +1,16 @@ +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // mysql database access info + $mysql_user="fred"; + $mysql_pw="apassword"; + $mysql_db="mydbname"; + + // where to put the eeprom config files + $bddb_cfgdir = '/tftpboot/bddb'; + + // what this database is called + $bddb_label = 'Hymod Board Database'; +?> diff --git a/qemu/roms/u-boot/tools/bddb/create_tables.sql b/qemu/roms/u-boot/tools/bddb/create_tables.sql new file mode 100644 index 000000000..a2a578867 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/create_tables.sql @@ -0,0 +1,90 @@ +# phpMyAdmin MySQL-Dump +# http://phpwizard.net/phpMyAdmin/ +# +# Host: localhost Database : hymod_bddb + +# (C) Copyright 2001 +# Murray Jensen <Murray.Jensen@csiro.au> +# CSIRO Manufacturing and Infrastructure Technology, Preston Lab + +# -------------------------------------------------------- +# +# Table structure for table 'boards' +# + +DROP TABLE IF EXISTS boards; +CREATE TABLE boards ( + serno int(10) unsigned zerofill NOT NULL auto_increment, + ethaddr char(17), + date date NOT NULL, + batch char(32), + type enum('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY') NOT NULL, + rev tinyint(3) unsigned zerofill NOT NULL, + location char(64), + comments text, + sdram0 enum('32M','64M','128M','256M','512M','1G','2G','4G'), + sdram1 enum('32M','64M','128M','256M','512M','1G','2G','4G'), + sdram2 enum('32M','64M','128M','256M','512M','1G','2G','4G'), + sdram3 enum('32M','64M','128M','256M','512M','1G','2G','4G'), + flash0 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'), + flash1 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'), + flash2 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'), + flash3 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'), + zbt0 enum('512K','1M','2M','4M','8M','16M'), + zbt1 enum('512K','1M','2M','4M','8M','16M'), + zbt2 enum('512K','1M','2M','4M','8M','16M'), + zbt3 enum('512K','1M','2M','4M','8M','16M'), + zbt4 enum('512K','1M','2M','4M','8M','16M'), + zbt5 enum('512K','1M','2M','4M','8M','16M'), + zbt6 enum('512K','1M','2M','4M','8M','16M'), + zbt7 enum('512K','1M','2M','4M','8M','16M'), + zbt8 enum('512K','1M','2M','4M','8M','16M'), + zbt9 enum('512K','1M','2M','4M','8M','16M'), + zbta enum('512K','1M','2M','4M','8M','16M'), + zbtb enum('512K','1M','2M','4M','8M','16M'), + zbtc enum('512K','1M','2M','4M','8M','16M'), + zbtd enum('512K','1M','2M','4M','8M','16M'), + zbte enum('512K','1M','2M','4M','8M','16M'), + zbtf enum('512K','1M','2M','4M','8M','16M'), + xlxtyp0 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'), + xlxtyp1 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'), + xlxtyp2 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'), + xlxtyp3 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'), + xlxspd0 enum('6','7','8','4','5','9','10','11','12'), + xlxspd1 enum('6','7','8','4','5','9','10','11','12'), + xlxspd2 enum('6','7','8','4','5','9','10','11','12'), + xlxspd3 enum('6','7','8','4','5','9','10','11','12'), + xlxtmp0 enum('COM','IND'), + xlxtmp1 enum('COM','IND'), + xlxtmp2 enum('COM','IND'), + xlxtmp3 enum('COM','IND'), + xlxgrd0 enum('NORMAL','ENGSAMP'), + xlxgrd1 enum('NORMAL','ENGSAMP'), + xlxgrd2 enum('NORMAL','ENGSAMP'), + xlxgrd3 enum('NORMAL','ENGSAMP'), + cputyp enum('MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)','MPC8560'), + cpuspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'), + cpmspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'), + busspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'), + hstype enum('AMCC-S2064A','Xilinx-Rockets'), + hschin enum('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'), + hschout enum('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'), + PRIMARY KEY (serno), + KEY serno (serno), + UNIQUE serno_2 (serno) +); + +# +# Table structure for table 'log' +# + +DROP TABLE IF EXISTS log; +CREATE TABLE log ( + logno int(10) unsigned zerofill NOT NULL auto_increment, + serno int(10) unsigned zerofill NOT NULL, + date date NOT NULL, + details text NOT NULL, + PRIMARY KEY (logno), + KEY logno (logno, serno, date), + UNIQUE logno_2 (logno) +); diff --git a/qemu/roms/u-boot/tools/bddb/defs.php b/qemu/roms/u-boot/tools/bddb/defs.php new file mode 100644 index 000000000..0b5060282 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/defs.php @@ -0,0 +1,710 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // contains mysql user id and password - keep secret + require("config.php"); + + if (isset($_REQUEST['logout'])) { + Header("status: 401 Unauthorized"); + Header("HTTP/1.0 401 Unauthorized"); + Header("WWW-authenticate: basic realm=\"$bddb_label\""); + + echo "<html><head><title>" . + "Access to '$bddb_label' Denied" . + "</title></head>\n"; + echo "<body bgcolor=#ffffff><br></br><br></br><center><h1>" . + "You must be an Authorised User " . + "to access the '$bddb_label'" . + "</h1>\n</center></body></html>\n"; + exit; + } + + // contents of the various enumerated types - if first item is + // empty ('') then the enum is allowed to be null (ie "not null" + // is not set on the column) + + // all column names in the database table + $columns = array( + 'serno','ethaddr','date','batch', + 'type','rev','location','comments', + 'sdram0','sdram1','sdram2','sdram3', + 'flash0','flash1','flash2','flash3', + 'zbt0','zbt1','zbt2','zbt3','zbt4','zbt5','zbt6','zbt7', + 'zbt8','zbt9','zbta','zbtb','zbtc','zbtd','zbte','zbtf', + 'xlxtyp0','xlxtyp1','xlxtyp2','xlxtyp3', + 'xlxspd0','xlxspd1','xlxspd2','xlxspd3', + 'xlxtmp0','xlxtmp1','xlxtmp2','xlxtmp3', + 'xlxgrd0','xlxgrd1','xlxgrd2','xlxgrd3', + 'cputyp','cpuspd','cpmspd','busspd', + 'hstype','hschin','hschout' + ); + + // board type + $type_vals = array('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY'); + + // Xilinx fpga types + $xlxtyp_vals = array('','XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'); + + // Xilinx fpga speeds + $xlxspd_vals = array('','6','7','8','4','5','9','10','11','12'); + + // Xilinx fpga temperatures (commercial or industrial) + $xlxtmp_vals = array('','COM','IND'); + + // Xilinx fpga grades (normal or engineering sample) + $xlxgrd_vals = array('','NORMAL','ENGSAMP'); + + // CPU types + $cputyp_vals = array('','MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)','MPC8560'); + + // CPU/BUS/CPM clock speeds + $clk_vals = array('','33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'); + + // sdram sizes (nbits array is for eeprom config file) + $sdram_vals = array('','32M','64M','128M','256M','512M','1G','2G','4G'); + $sdram_nbits = array(0,25,26,27,28,29,30,31,32); + + // flash sizes (nbits array is for eeprom config file) + $flash_vals = array('','4M','8M','16M','32M','64M','128M','256M','512M','1G'); + $flash_nbits = array(0,22,23,24,25,26,27,28,29,30); + + // zbt ram sizes (nbits array is for write into eeprom config file) + $zbt_vals = array('','512K','1M','2M','4M','8M','16M'); + $zbt_nbits = array(0,19,20,21,22,23,24); + + // high-speed serial attributes + $hstype_vals = array('','AMCC-S2064A','Xilinx-Rockets'); + $hschin_vals = array('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'); + $hschout_vals = array('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'); + + // value filters - used when outputting html + function rev_filter($num) { + if ($num == 0) + return "001"; + else + return sprintf("%03d", $num); + } + + function text_filter($str) { + return urldecode($str); + } + + mt_srand(time() | getmypid()); + + // set up MySQL connection + mysql_connect("", $mysql_user, $mysql_pw) || die("cannot connect"); + mysql_select_db($mysql_db) || die("cannot select db"); + + // page header + function pg_head($title) + { + echo "<html>\n<head>\n"; + echo "<link rel=stylesheet href=\"bddb.css\" type=\"text/css\" title=\"style sheet\"></link>\n"; + echo "<title>$title</title>\n"; + echo "</head>\n"; + echo "<body>\n"; + echo "<center><h1>$title</h1></center>\n"; + echo "<hr></hr>\n"; + } + + // page footer + function pg_foot() + { + echo "<hr></hr>\n"; + echo "<table width=\"100%\"><tr><td align=left>\n<address>" . + "If you have any problems, email " . + "<a href=\"mailto:Murray.Jensen@csiro.au\">" . + "Murray Jensen" . + "</a></address>\n" . + "</td><td align=right>\n" . + "<a href=\"index.php?logout=true\">logout</a>\n" . + "</td></tr></table>\n"; + echo "<p><small><i>Made with " . + "<a href=\"http://kyber.dk/phpMyBuilder/\">" . + "Kyber phpMyBuilder</a></i></small></p>\n"; + echo "</body>\n"; + echo "</html>\n"; + } + + // some support functions + + if (!function_exists('array_search')) { + + function array_search($needle, $haystack, $strict = false) { + + if (is_array($haystack) && count($haystack)) { + + $ntype = gettype($needle); + + foreach ($haystack as $key => $value) { + + if ($value == $needle && (!$strict || + gettype($value) == $ntype)) + return $key; + } + } + + return false; + } + } + + if (!function_exists('in_array')) { + + function in_array($needle, $haystack, $strict = false) { + + if (is_array($haystack) && count($haystack)) { + + $ntype = gettype($needle); + + foreach ($haystack as $key => $value) { + + if ($value == $needle && (!$strict || + gettype($value) == $ntype)) + return true; + } + } + + return false; + } + } + + function key_in_array($key, $array) { + return in_array($key, array_keys($array), true); + } + + function enum_to_index($name, $vals) { + $index = array_search($GLOBALS[$name], $vals); + if ($vals[0] != '') + $index++; + return $index; + } + + // fetch a value from an array - return empty string is not present + function get_key_value($key, $array) { + if (key_in_array($key, $array)) + return $array[$key]; + else + return ''; + } + + function fprintf() { + $n = func_num_args(); + if ($n < 2) + return FALSE; + $a = func_get_args(); + $fp = array_shift($a); + $x = "\$s = sprintf"; + $sep = '('; + foreach ($a as $z) { + $x .= "$sep'$z'"; + $sep = ','; + } + $x .= ');'; + eval($x); + $l = strlen($s); + $r = fwrite($fp, $s, $l); + if ($r != $l) + return FALSE; + else + return TRUE; + } + + // functions to display (print) a database table and its columns + + function begin_table($ncols) { + global $table_ncols; + $table_ncols = $ncols; + echo "<table align=center width=\"100%\"" + . " border=1 cellpadding=4 cols=$table_ncols>\n"; + } + + function begin_field($name, $span = 0) { + global $table_ncols; + echo "<tr valign=top>\n"; + echo "\t<th align=center>$name</th>\n"; + if ($span <= 0) + $span = $table_ncols - 1; + if ($span > 1) + echo "\t<td colspan=$span>\n"; + else + echo "\t<td>\n"; + } + + function cont_field($span = 1) { + echo "\t</td>\n"; + if ($span > 1) + echo "\t<td colspan=$span>\n"; + else + echo "\t<td>\n"; + } + + function end_field() { + echo "\t</td>\n"; + echo "</tr>\n"; + } + + function end_table() { + echo "</table>\n"; + } + + function print_field($name, $array, $size = 0, $filt='') { + + begin_field($name); + + if (key_in_array($name, $array)) + $value = $array[$name]; + else + $value = ''; + + if ($filt != '') + $value = $filt($value); + + echo "\t\t<input name=$name value=\"$value\""; + if ($size > 0) + echo " size=$size maxlength=$size"; + echo "></input>\n"; + + end_field(); + } + + function print_field_multiline($name, $array, $cols, $rows, $filt='') { + + begin_field($name); + + if (key_in_array($name, $array)) + $value = $array[$name]; + else + $value = ''; + + if ($filt != '') + $value = $filt($value); + + echo "\t\t<textarea name=$name " . + "cols=$cols rows=$rows wrap=off>\n"; + echo "$value"; + echo "</textarea>\n"; + + end_field(); + } + + // print a mysql ENUM as an html RADIO INPUT + function print_enum($name, $array, $vals, $def = -1) { + + begin_field($name); + + if (key_in_array($name, $array)) + $chk = array_search($array[$name], $vals, FALSE); + else + $chk = $def; + + $nval = count($vals); + + for ($i = 0; $i < $nval; $i++) { + + $val = $vals[$i]; + if ($val == '') + $pval = "none"; + else + $pval = "$val"; + + printf("\t\t<input type=radio name=$name" + . " value=\"$val\"%s>$pval</input>\n", + $i == $chk ? " checked" : ""); + } + + end_field(); + } + + // print a mysql ENUM as an html SELECT INPUT + function print_enum_select($name, $array, $vals, $def = -1) { + + begin_field($name); + + echo "\t\t<select name=$name>\n"; + + if (key_in_array($name, $array)) + $chk = array_search($array[$name], $vals, FALSE); + else + $chk = $def; + + $nval = count($vals); + + for ($i = 0; $i < $nval; $i++) { + + $val = $vals[$i]; + if ($val == '') + $pval = "none"; + else + $pval = "$val"; + + printf("\t\t\t<option " . + "value=\"%s\"%s>%s</option>\n", + $val, $i == $chk ? " selected" : "", $pval); + } + + echo "\t\t</select>\n"; + + end_field(); + } + + // print a group of mysql ENUMs (e.g. name0,name1,...) as an html SELECT + function print_enum_multi($base, $array, $vals, $cnt, $defs, $grp = 0) { + + global $table_ncols; + + if ($grp <= 0) + $grp = $cnt; + $ncell = $cnt / $grp; + $span = ($table_ncols - 1) / $ncell; + + begin_field($base, $span); + + $nval = count($vals); + + for ($i = 0; $i < $cnt; $i++) { + + if ($i > 0 && ($i % $grp) == 0) + cont_field($span); + + $name = sprintf("%s%x", $base, $i); + + echo "\t\t<select name=$name>\n"; + + if (key_in_array($name, $array)) + $ai = array_search($array[$name], $vals, FALSE); + else { + if (key_in_array($i, $defs)) + $ai = $defs[$i]; + else + $ai = 0; + } + + for ($j = 0; $j < $nval; $j++) { + + $val = $vals[$j]; + if ($val == '') + $pval = " "; + else + $pval = "$val"; + + printf("\t\t\t<option " . + "value=\"%s\"%s>%s</option>\n", + $val, + $j == $ai ? " selected" : "", + $pval); + } + + echo "\t\t</select>\n"; + } + + end_field(); + } + + // functions to handle the form input + + // fetch all the parts of an "enum_multi" into a string suitable + // for a MySQL query + function gather_enum_multi_query($base, $cnt) { + + $retval = ''; + + for ($i = 0; $i < $cnt; $i++) { + + $name = sprintf("%s%x", $base, $i); + + if (isset($_REQUEST[$name])) { + $retval .= sprintf(", %s='%s'", + $name, $_REQUEST[$name]); + } + } + + return $retval; + } + + // fetch all the parts of an "enum_multi" into a string suitable + // for a display e.g. in an html table cell + function gather_enum_multi_print($base, $cnt, $array) { + + $retval = ''; + + for ($i = 0; $i < $cnt; $i++) { + + $name = sprintf("%s%x", $base, $i); + + if ($array[$name] != '') { + if ($retval != '') + $retval .= ','; + $retval .= $array[$name]; + } + } + + return $retval; + } + + // fetch all the parts of an "enum_multi" into a string suitable + // for writing to the eeprom data file + function gather_enum_multi_write($base, $cnt, $vals, $xfrm = array()) { + + $retval = ''; + + for ($i = 0; $i < $cnt; $i++) { + + $name = sprintf("%s%x", $base, $i); + + if ($GLOBALS[$name] != '') { + if ($retval != '') + $retval .= ','; + $index = enum_to_index($name, $vals); + if ($xfrm != array()) + $retval .= $xfrm[$index]; + else + $retval .= $index; + } + } + + return $retval; + } + + // count how many parts of an "enum_multi" are actually set + function count_enum_multi($base, $cnt) { + + $retval = 0; + + for ($i = 0; $i < $cnt; $i++) { + + $name = sprintf("%s%x", $base, $i); + + if (isset($_REQUEST[$name])) + $retval++; + } + + return $retval; + } + + // ethernet address functions + + // generate a (possibly not unique) random vendor ethernet address + // (setting bit 6 in the ethernet address - motorola wise i.e. bit 0 + // is the most significant bit - means it is not an assigned ethernet + // address - it is a "locally administered" address). Also, make sure + // it is NOT a multicast ethernet address (by setting bit 7 to 0). + // e.g. the first byte of all ethernet addresses generated here will + // have 2 in the bottom two bits (incidentally, these are the first + // two bits transmitted on the wire, since the octets in ethernet + // addresses are transmitted LSB first). + + function gen_eth_addr($serno) { + + $ethaddr_hgh = (mt_rand(0, 65535) & 0xfeff) | 0x0200; + $ethaddr_mid = mt_rand(0, 65535); + $ethaddr_low = mt_rand(0, 65535); + + return sprintf("%02lx:%02lx:%02lx:%02lx:%02lx:%02lx", + $ethaddr_hgh >> 8, $ethaddr_hgh & 0xff, + $ethaddr_mid >> 8, $ethaddr_mid & 0xff, + $ethaddr_low >> 8, $ethaddr_low & 0xff); + } + + // check that an ethernet address is valid + function eth_addr_is_valid($ethaddr) { + + $ethbytes = split(':', $ethaddr); + + if (count($ethbytes) != 6) + return FALSE; + + for ($i = 0; $i < 6; $i++) { + $ethbyte = $ethbytes[$i]; + if (!ereg('^[0-9a-f][0-9a-f]$', $ethbyte)) + return FALSE; + } + + return TRUE; + } + + // write a simple eeprom configuration file + function write_eeprom_cfg_file() { + + global $sernos, $nsernos, $bddb_cfgdir, $numerrs, $cfgerrs; + global $date, $batch, $type_vals, $rev; + global $sdram_vals, $sdram_nbits; + global $flash_vals, $flash_nbits; + global $zbt_vals, $zbt_nbits; + global $xlxtyp_vals, $xlxspd_vals, $xlxtmp_vals, $xlxgrd_vals; + global $cputyp, $cputyp_vals, $clk_vals; + global $hstype, $hstype_vals, $hschin, $hschout; + + $numerrs = 0; + $cfgerrs = array(); + + for ($i = 0; $i < $nsernos; $i++) { + + $serno = sprintf("%010d", $sernos[$i]); + + $wfp = @fopen($bddb_cfgdir . "/$serno.cfg", "w"); + if (!$wfp) { + $cfgerrs[$i] = 'file create fail'; + $numerrs++; + continue; + } + set_file_buffer($wfp, 0); + + if (!fprintf($wfp, "serno=%d\n", $sernos[$i])) { + $cfgerrs[$i] = 'cfg wr fail (serno)'; + fclose($wfp); + $numerrs++; + continue; + } + + if (!fprintf($wfp, "date=%s\n", $date)) { + $cfgerrs[$i] = 'cfg wr fail (date)'; + fclose($wfp); + $numerrs++; + continue; + } + + if ($batch != '') { + if (!fprintf($wfp, "batch=%s\n", $batch)) { + $cfgerrs[$i] = 'cfg wr fail (batch)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + $typei = enum_to_index("type", $type_vals); + if (!fprintf($wfp, "type=%d\n", $typei)) { + $cfgerrs[$i] = 'cfg wr fail (type)'; + fclose($wfp); + $numerrs++; + continue; + } + + if (!fprintf($wfp, "rev=%d\n", $rev)) { + $cfgerrs[$i] = 'cfg wr fail (rev)'; + fclose($wfp); + $numerrs++; + continue; + } + + $s = gather_enum_multi_write("sdram", 4, + $sdram_vals, $sdram_nbits); + if ($s != '') { + $b = fprintf($wfp, "sdram=%s\n", $s); + if (!$b) { + $cfgerrs[$i] = 'cfg wr fail (sdram)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + $s = gather_enum_multi_write("flash", 4, + $flash_vals, $flash_nbits); + if ($s != '') { + $b = fprintf($wfp, "flash=%s\n", $s); + if (!$b) { + $cfgerrs[$i] = 'cfg wr fail (flash)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + $s = gather_enum_multi_write("zbt", 16, + $zbt_vals, $zbt_nbits); + if ($s != '') { + $b = fprintf($wfp, "zbt=%s\n", $s); + if (!$b) { + $cfgerrs[$i] = 'cfg wr fail (zbt)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + $s = gather_enum_multi_write("xlxtyp", 4, $xlxtyp_vals); + if ($s != '') { + $b = fprintf($wfp, "xlxtyp=%s\n", $s); + if (!$b) { + $cfgerrs[$i] = 'cfg wr fail (xlxtyp)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + $s = gather_enum_multi_write("xlxspd", 4, $xlxspd_vals); + if ($s != '') { + $b = fprintf($wfp, "xlxspd=%s\n", $s); + if (!$b) { + $cfgerrs[$i] = 'cfg wr fail (xlxspd)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + $s = gather_enum_multi_write("xlxtmp", 4, $xlxtmp_vals); + if ($s != '') { + $b = fprintf($wfp, "xlxtmp=%s\n", $s); + if (!$b) { + $cfgerrs[$i] = 'cfg wr fail (xlxtmp)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + $s = gather_enum_multi_write("xlxgrd", 4, $xlxgrd_vals); + if ($s != '') { + $b = fprintf($wfp, "xlxgrd=%s\n", $s); + if (!$b) { + $cfgerrs[$i] = 'cfg wr fail (xlxgrd)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + if ($cputyp != '') { + $cputypi = enum_to_index("cputyp",$cputyp_vals); + $cpuspdi = enum_to_index("cpuspd", $clk_vals); + $busspdi = enum_to_index("busspd", $clk_vals); + $cpmspdi = enum_to_index("cpmspd", $clk_vals); + $b = fprintf($wfp, "cputyp=%d\ncpuspd=%d\n" . + "busspd=%d\ncpmspd=%d\n", + $cputypi, $cpuspdi, $busspdi, $cpmspdi); + if (!$b) { + $cfgerrs[$i] = 'cfg wr fail (cputyp)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + if ($hstype != '') { + $hstypei = enum_to_index("hstype",$hstype_vals); + $b = fprintf($wfp, "hstype=%d\n" . + "hschin=%s\nhschout=%s\n", + $hstypei, $hschin, $hschout); + if (!$b) { + $cfgerrs[$i] = 'cfg wr fail (hstype)'; + fclose($wfp); + $numerrs++; + continue; + } + } + + if (!fclose($wfp)) { + $cfgerrs[$i] = 'file cls fail'; + $numerrs++; + } + } + + return $numerrs; + } +?> diff --git a/qemu/roms/u-boot/tools/bddb/dodelete.php b/qemu/roms/u-boot/tools/bddb/dodelete.php new file mode 100644 index 000000000..4839e36e6 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/dodelete.php @@ -0,0 +1,65 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // dodelete page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - Delete Board Results"); + + if (!isset($_REQUEST['serno'])) + die("the board serial number was not specified"); + $serno=intval($_REQUEST['serno']); + + mysql_query("delete from boards where serno=$serno"); + + if(mysql_errno()) { + $errstr = mysql_error(); + echo "\t<font size=+4>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe following error was encountered:\n"; + echo "\t\t</p>\n"; + echo "\t\t<center>\n"; + printf("\t\t\t<b>%s</b>\n", $errstr); + echo "\t\t</center>\n"; + echo "\t</font>\n"; + } + else { + echo "\t<font size=+2>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe board with serial number <b>$serno</b> was" + . " successfully deleted\n"; + mysql_query("delete from log where serno=$serno"); + if (mysql_errno()) { + $errstr = mysql_error(); + echo "\t\t\t<font size=+4>\n"; + echo "\t\t\t\t<p>\n"; + echo "\t\t\t\t\tBut the following error occurred " . + "when deleting the log entries:\n"; + echo "\t\t\t\t</p>\n"; + echo "\t\t\t\t<center>\n"; + printf("\t\t\t\t\t<b>%s</b>\n", $errstr); + echo "\t\t\t\t</center>\n"; + echo "\t\t\t</font>\n"; + } + echo "\t\t</p>\n"; + echo "\t</font>\n"; + } +?> +<p> +<table width="100%"> +<tr> + <td align=center> + <a href="browse.php">Back to Browse</a> + </td> + <td align=center> + <a href="index.php">Back to Start</a> + </td> +</tr> +</table> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/dodellog.php b/qemu/roms/u-boot/tools/bddb/dodellog.php new file mode 100644 index 000000000..9dd78c11b --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/dodellog.php @@ -0,0 +1,57 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // dodelete page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - Delete Log Entry Results"); + + if (!isset($_REQUEST['serno'])) + die("the board serial number was not specified"); + $serno=intval($_REQUEST['serno']); + + if (!isset($_REQUEST['logno']) || $_REQUEST['logno'] == 0) + die("the log entry number not specified!"); + $logno=$_REQUEST['logno']; + + mysql_query("delete from log where serno=$serno and logno=$logno"); + + if(mysql_errno()) { + $errstr = mysql_error(); + echo "\t<font size=+4>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe following error was encountered:\n"; + echo "\t\t</p>\n"; + echo "\t\t<center>\n"; + printf("\t\t\t<b>%s</b>\n", $errstr); + echo "\t\t</center>\n"; + echo "\t</font>\n"; + } + else { + echo "\t<font size=+2>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe log entry with log number <b>$logno</b>\n"; + echo "\t\t\tand serial number <b>$serno</b> "; + echo "was successfully deleted\n"; + echo "\t\t</p>\n"; + echo "\t</font>\n"; + } +?> +<p> +<table width="100%"> +<tr> + <td align=center> + <a href="brlog.php?serno=<?php echo "$serno"; ?>">Back to Log</a> + </td> + <td align=center> + <a href="index.php">Back to Start</a> + </td> +</tr> +</table> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/doedit.php b/qemu/roms/u-boot/tools/bddb/doedit.php new file mode 100644 index 000000000..13fbb6947 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/doedit.php @@ -0,0 +1,186 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // doedit page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - Edit Board Results"); + + if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '') + die("the board serial number was not specified"); + $serno=intval($_REQUEST['serno']); + + $query="update boards set"; + + if (isset($_REQUEST['ethaddr'])) { + $ethaddr=$_REQUEST['ethaddr']; + if (!eth_addr_is_valid($ethaddr)) + die("ethaddr is invalid ('$ethaddr')"); + $query.=" ethaddr='$ethaddr',"; + } + + if (isset($_REQUEST['date'])) { + $date=$_REQUEST['date']; + list($y, $m, $d) = split("-", $date); + if (!checkdate($m, $d, $y) || $y < 1999) + die("date is invalid (input '$date', " . + "yyyy-mm-dd '$y-$m-$d')"); + $query.=" date='$date'"; + } + + if (isset($_REQUEST['batch'])) { + $batch=$_REQUEST['batch']; + if (strlen($batch) > 32) + die("batch field too long (>32)"); + $query.=", batch='$batch'"; + } + + if (isset($_REQUEST['type'])) { + $type=$_REQUEST['type']; + if (!in_array($type, $type_vals)) + die("Invalid type ($type) specified"); + $query.=", type='$type'"; + } + + if (isset($_REQUEST['rev'])) { + $rev=$_REQUEST['rev']; + if (($rev = intval($rev)) <= 0 || $rev > 255) + die("Revision number is invalid ($rev)"); + $query.=sprintf(", rev=%d", $rev); + } + + if (isset($_REQUEST['location'])) { + $location=$_REQUEST['location']; + if (strlen($location) > 64) + die("location field too long (>64)"); + $query.=", location='$location'"; + } + + if (isset($_REQUEST['comments'])) + $comments=$_REQUEST['comments']; + $query.=", comments='" . rawurlencode($comments) . "'"; + + $query.=gather_enum_multi_query("sdram", 4); + + $query.=gather_enum_multi_query("flash", 4); + + $query.=gather_enum_multi_query("zbt", 16); + + $query.=gather_enum_multi_query("xlxtyp", 4); + $nxlx = count_enum_multi("xlxtyp", 4); + + $query.=gather_enum_multi_query("xlxspd", 4); + if (count_enum_multi("xlxspd", 4) != $nxlx) + die("number of xilinx speeds not same as number of types"); + + $query.=gather_enum_multi_query("xlxtmp", 4); + if (count_enum_multi("xlxtmp", 4) != $nxlx) + die("number of xilinx temps. not same as number of types"); + + $query.=gather_enum_multi_query("xlxgrd", 4); + if (count_enum_multi("xlxgrd", 4) != $nxlx) + die("number of xilinx grades not same as number of types"); + + if (isset($_REQUEST['cputyp'])) { + $cputyp=$_REQUEST['cputyp']; + $query.=", cputyp='$cputyp'"; + if (!isset($_REQUEST['cpuspd']) || $_REQUEST['cpuspd'] == '') + die("must specify cpu speed if cpu type is defined"); + $cpuspd=$_REQUEST['cpuspd']; + $query.=", cpuspd='$cpuspd'"; + if (!isset($_REQUEST['cpmspd']) || $_REQUEST['cpmspd'] == '') + die("must specify cpm speed if cpu type is defined"); + $cpmspd=$_REQUEST['cpmspd']; + $query.=", cpmspd='$cpmspd'"; + if (!isset($_REQUEST['busspd']) || $_REQUEST['busspd'] == '') + die("must specify bus speed if cpu type is defined"); + $busspd=$_REQUEST['busspd']; + $query.=", busspd='$busspd'"; + } + else { + if (isset($_REQUEST['cpuspd'])) + die("can't specify cpu speed if there is no cpu"); + if (isset($_REQUEST['cpmspd'])) + die("can't specify cpm speed if there is no cpu"); + if (isset($_REQUEST['busspd'])) + die("can't specify bus speed if there is no cpu"); + } + + if (isset($_REQUEST['hschin'])) { + $hschin=$_REQUEST['hschin']; + if (($hschin = intval($hschin)) < 0 || $hschin > 4) + die("Invalid number of hs input chans ($hschin)"); + } + else + $hschin = 0; + if (isset($_REQUEST['hschout'])) { + $hschout=$_REQUEST['hschout']; + if (($hschout = intval($hschout)) < 0 || $hschout > 4) + die("Invalid number of hs output chans ($hschout)"); + } + else + $hschout = 0; + if (isset($_REQUEST['hstype'])) { + $hstype=$_REQUEST['hstype']; + $query.=", hstype='$hstype'"; + } + else { + if ($_REQUEST['hschin'] != 0) + die("number of high-speed input channels must be zero" + . " if high-speed chip is not present"); + if ($_REQUEST['hschout'] != 0) + die("number of high-speed output channels must be zero" + . " if high-speed chip is not present"); + } + $query.=", hschin='$hschin'"; + $query.=", hschout='$hschout'"; + + $query.=" where serno=$serno"; + + mysql_query($query); + if(mysql_errno()) { + $errstr = mysql_error(); + echo "\t<font size=+4>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe following error was encountered:\n"; + echo "\t\t</p>\n"; + echo "\t\t<center>\n"; + printf("\t\t\t<b>%s</b>\n", $errstr); + echo "\t\t</center>\n"; + echo "\t</font>\n"; + } + else { + $sernos = array($serno); + $nsernos = 1; + + write_eeprom_cfg_file(); + + echo "\t<font size=+2>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe board with serial number <b>$serno</b> was" + . " successfully updated"; + if ($numerrs > 0) { + $errstr = $cfgerrs[0]; + echo "<br>\n\t\t\t"; + echo "(but the cfg file update failed: $errstr)"; + } + echo "\n"; + echo "\t\t</p>\n"; + echo "\t</font>\n"; + } + +?> +<p> +<table align=center width="100%"> +<tr> + <td align=center><a href="browse.php">Back to Browse</a></td> + <td align=center><a href="index.php">Back to Start</a></td> +</tr> +</table> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/doedlog.php b/qemu/roms/u-boot/tools/bddb/doedlog.php new file mode 100644 index 000000000..7009aa7da --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/doedlog.php @@ -0,0 +1,76 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // doedit page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - Edit Log Entry Results"); + + if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '') + die("the board serial number was not specified"); + $serno=intval($_REQUEST['serno']); + + if (!isset($_REQUEST['logno']) || $_REQUEST['logno'] == '') + die("log number not specified!"); + $logno=intval($_REQUEST['logno']); + + $query="update log set"; + + if (isset($_REQUEST['date'])) { + $date=$_REQUEST['date']; + list($y, $m, $d) = split("-", $date); + if (!checkdate($m, $d, $y) || $y < 1999) + die("date is invalid (input '$date', " . + "yyyy-mm-dd '$y-$m-$d')"); + $query.=" date='$date'"; + } + + if (isset($_REQUEST['who'])) { + $who=$_REQUEST['who']; + $query.=", who='" . $who . "'"; + } + + if (isset($_REQUEST['details'])) { + $details=$_REQUEST['details']; + $query.=", details='" . rawurlencode($details) . "'"; + } + + $query.=" where serno=$serno and logno=$logno"; + + mysql_query($query); + if(mysql_errno()) { + $errstr = mysql_error(); + echo "\t<font size=+4>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe following error was encountered:\n"; + echo "\t\t</p>\n"; + echo "\t\t<center>\n"; + printf("\t\t\t<b>%s</b>\n", $errstr); + echo "\t\t</center>\n"; + echo "\t</font>\n"; + } + else { + echo "\t<font size=+2>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe log entry with log number <b>$logno</b> and\n"; + echo "\t\t\tserial number <b>$serno</b> "; + echo "was successfully updated\n"; + echo "\t\t</p>\n"; + echo "\t</font>\n"; + } + +?> +<p> +<table align=center width="100%"> +<tr> + <td align=center><a href="brlog.php?serno=<?php echo "$serno"; ?>">Back to Log</a></td> + <td align=center><a href="index.php">Back to Start</a></td> +</tr> +</table> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/donew.php b/qemu/roms/u-boot/tools/bddb/donew.php new file mode 100644 index 000000000..39b2c78fc --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/donew.php @@ -0,0 +1,230 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // doedit page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - Board Registration Results"); + + if (isset($_REQUEST['serno'])) { + $serno=$_REQUEST['serno']; + die("serial number must not be set ($serno) when Creating!"); + } + + $query="update boards set"; + + list($y, $m, $d) = split("-", $date); + if (!checkdate($m, $d, $y) || $y < 1999) + die("date is invalid (input '$date', yyyy-mm-dd '$y-$m-$d')"); + $query.=" date='$date'"; + + if ($batch != '') { + if (strlen($batch) > 32) + die("batch field too long (>32)"); + $query.=", batch='$batch'"; + } + + if (!in_array($type, $type_vals)) + die("Invalid type ($type) specified"); + $query.=", type='$type'"; + + if (($rev = intval($rev)) <= 0 || $rev > 255) + die("Revision number is invalid ($rev)"); + $query.=sprintf(", rev=%d", $rev); + + $query.=gather_enum_multi_query("sdram", 4); + + $query.=gather_enum_multi_query("flash", 4); + + $query.=gather_enum_multi_query("zbt", 16); + + $query.=gather_enum_multi_query("xlxtyp", 4); + $nxlx = count_enum_multi("xlxtyp", 4); + + $query.=gather_enum_multi_query("xlxspd", 4); + if (count_enum_multi("xlxspd", 4) != $nxlx) + die("number of xilinx speeds not same as number of types"); + + $query.=gather_enum_multi_query("xlxtmp", 4); + if (count_enum_multi("xlxtmp", 4) != $nxlx) + die("number of xilinx temps. not same as number of types"); + + $query.=gather_enum_multi_query("xlxgrd", 4); + if (count_enum_multi("xlxgrd", 4) != $nxlx) + die("number of xilinx grades not same as number of types"); + + if ($cputyp == '') { + if ($cpuspd != '') + die("can't specify cpu speed if there is no cpu"); + if ($cpmspd != '') + die("can't specify cpm speed if there is no cpu"); + if ($busspd != '') + die("can't specify bus speed if there is no cpu"); + } + else { + $query.=", cputyp='$cputyp'"; + if ($cpuspd == '') + die("must specify cpu speed if cpu type is defined"); + $query.=", cpuspd='$cpuspd'"; + if ($cpmspd == '') + die("must specify cpm speed if cpu type is defined"); + $query.=", cpmspd='$cpmspd'"; + if ($busspd == '') + die("must specify bus speed if cpu type is defined"); + $query.=", busspd='$busspd'"; + } + + if (($hschin = intval($hschin)) < 0 || $hschin > 4) + die("Invalid number of hs input chans ($hschin)"); + if (($hschout = intval($hschout)) < 0 || $hschout > 4) + die("Invalid number of hs output chans ($hschout)"); + if ($hstype == '') { + if ($hschin != 0) + die("number of high-speed input channels must be zero" + . " if high-speed chip is not present"); + if ($hschout != 0) + die("number of high-speed output channels must be zero" + . " if high-speed chip is not present"); + } + else + $query.=", hstype='$hstype'"; + $query.=", hschin='$hschin'"; + $query.=", hschout='$hschout'"; + + // echo "final query = '$query'<br>\n"; + + $quant = intval($quant); + if ($quant <= 0) $quant = 1; + + $sernos = array(); + if ($geneths) + $ethaddrs = array(); + + $sqlerr = ''; + + while ($quant-- > 0) { + + mysql_query("insert into boards (serno) values (null)"); + if (mysql_errno()) { + $sqlerr = mysql_error(); + break; + } + + $serno = mysql_insert_id(); + if (!$serno) { + $sqlerr = "couldn't allocate new serial number"; + break; + } + + mysql_query($query . " where serno=$serno"); + if (mysql_errno()) { + $sqlerr = mysql_error(); + break; + } + + array_push($sernos, $serno); + + if ($geneths) { + + $ethaddr = gen_eth_addr($serno); + + mysql_query("update boards set ethaddr='$ethaddr'" . + " where serno=$serno"); + if (mysql_errno()) { + $sqlerr = mysql_error(); + + array_push($ethaddrs, + "<font color=#ff0000><b>" . + "db save fail" . + "</b></font>"); + break; + } + + array_push($ethaddrs, $ethaddr); + } + } + + $nsernos = count($sernos); + + if ($nsernos > 0) { + + write_eeprom_cfg_file(); + + echo "<font size=+2>\n"; + echo "\t<p>\n"; + echo "\t\tThe following board serial numbers were" + . " successfully allocated"; + if ($numerrs > 0) + echo " (but with $numerrs cfg file error" . + ($numerrs > 1 ? "s" : "") . ")"; + echo ":\n"; + echo "\t</p>\n"; + + echo "</font>\n"; + + echo "<table align=center width=\"100%\">\n"; + echo "<tr>\n"; + echo "\t<th>Serial Number</th>\n"; + if ($numerrs > 0) + echo "\t<th>Cfg File Errs</th>\n"; + if ($geneths) + echo "\t<th>Ethernet Address</th>\n"; + echo "</tr>\n"; + + for ($i = 0; $i < $nsernos; $i++) { + + $serno = sprintf("%010d", $sernos[$i]); + + echo "<tr>\n"; + + echo "\t<td align=center><font size=+2>" . + "<b>$serno</b></font></td>\n"; + + if ($numerrs > 0) { + if (($errstr = $cfgerrs[$i]) == '') + $errstr = ' '; + echo "\t<td align=center>" . + "<font size=+2 color=#ff0000><b>" . + $errstr . + "</b></font></td>\n"; + } + + if ($geneths) { + echo "\t<td align=center>" . + "<font size=+2 color=#00ff00><b>" . + $ethaddrs[$i] . + "</b></font></td>\n"; + } + + echo "</tr>\n"; + } + + echo "</table>\n"; + } + + if ($sqlerr != '') { + echo "\t<font size=+4>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe following SQL error was encountered:\n"; + echo "\t\t</p>\n"; + echo "\t\t<center>\n"; + printf("\t\t\t<b>%s</b>\n", $sqlerr); + echo "\t\t</center>\n"; + echo "\t</font>\n"; + } + +?> +<p> +<table align=center width="100%"> +<tr> + <td align=center><a href="browse.php">Go to Browse</a></td> + <td align=center><a href="index.php">Back to Start</a></td> +</tr> +</table> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/donewlog.php b/qemu/roms/u-boot/tools/bddb/donewlog.php new file mode 100644 index 000000000..7635d2992 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/donewlog.php @@ -0,0 +1,86 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // doedit page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - Add Log Entry Results"); + + if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '') + die("serial number not specified!"); + $serno=intval($_REQUEST['serno']); + + if (isset($_REQUEST['logno'])) { + $logno=$_REQUEST['logno']; + die("log number must not be set ($logno) when Creating!"); + } + + $query="update log set serno=$serno"; + + list($y, $m, $d) = split("-", $date); + if (!checkdate($m, $d, $y) || $y < 1999) + die("date is invalid (input '$date', yyyy-mm-dd '$y-$m-$d')"); + $query.=", date='$date'"; + + if (isset($_REQUEST['who'])) { + $who=$_REQUEST['who']; + $query.=", who='" . $who . "'"; + } + + if (isset($_REQUEST['details'])) { + $details=$_REQUEST['details']; + $query.=", details='" . rawurlencode($details) . "'"; + } + + // echo "final query = '$query'<br>\n"; + + $sqlerr = ''; + + mysql_query("insert into log (logno) values (null)"); + if (mysql_errno()) + $sqlerr = mysql_error(); + else { + $logno = mysql_insert_id(); + if (!$logno) + $sqlerr = "couldn't allocate new serial number"; + else { + mysql_query($query . " where logno=$logno"); + if (mysql_errno()) + $sqlerr = mysql_error(); + } + } + + if ($sqlerr == '') { + echo "<font size=+2>\n"; + echo "\t<p>\n"; + echo "\t\tA log entry with log number '$logno' was " . + "added to the board with serial number '$serno'\n"; + echo "\t</p>\n"; + echo "</font>\n"; + } + else { + echo "\t<font size=+4>\n"; + echo "\t\t<p>\n"; + echo "\t\t\tThe following SQL error was encountered:\n"; + echo "\t\t</p>\n"; + echo "\t\t<center>\n"; + printf("\t\t\t<b>%s</b>\n", $sqlerr); + echo "\t\t</center>\n"; + echo "\t</font>\n"; + } + +?> +<p></p> +<table width="100%"> +<tr> + <td align=center><a href="brlog.php?serno=<?php echo "$serno"; ?>">Go to Browse</a></td> + <td align=center><a href="index.php">Back to Start</a></td> +</tr> +</table> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/edit.php b/qemu/roms/u-boot/tools/bddb/edit.php new file mode 100644 index 000000000..dd8c26c5c --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/edit.php @@ -0,0 +1,131 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // edit page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - Edit Board Registration"); + + if ($serno == 0) + die("serial number not specified or invalid!"); + + $pserno = sprintf("%010d", $serno); + + echo "<center><b><font size=+2>"; + echo "Board Serial Number: $pserno"; + echo "</font></b></center>\n"; + +?> +<p> +<form action=doedit.php method=POST> +<?php + echo "<input type=hidden name=serno value=$serno>\n"; + + $r=mysql_query("select * from boards where serno=$serno"); + $row=mysql_fetch_array($r); + if(!$row) die("no record of serial number '$serno' in database"); + + begin_table(5); + + // ethaddr char(17) + print_field("ethaddr", $row, 17); + + // date date + print_field("date", $row); + + // batch char(32) + print_field("batch", $row, 32); + + // type enum('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY') + print_enum("type", $row, $type_vals); + + // rev tinyint(3) unsigned zerofill + print_field("rev", $row, 3, 'rev_filter'); + + // location char(64) + print_field("location", $row, 64); + + // comments text + print_field_multiline("comments", $row, 60, 10, 'text_filter'); + + // sdram[0-3] enum('32M','64M','128M','256M') + print_enum_multi("sdram", $row, $sdram_vals, 4, array()); + + // flash[0-3] enum('4M','8M','16M','32M','64M') + print_enum_multi("flash", $row, $flash_vals, 4, array()); + + // zbt[0-f] enum('512K','1M','2M','4M') + print_enum_multi("zbt", $row, $zbt_vals, 16, array()); + + // xlxtyp[0-3] enum('XCV300E','XCV400E','XCV600E') + print_enum_multi("xlxtyp", $row, $xlxtyp_vals, 4, array(), 1); + + // xlxspd[0-3] enum('6','7','8') + print_enum_multi("xlxspd", $row, $xlxspd_vals, 4, array(), 1); + + // xlxtmp[0-3] enum('COM','IND') + print_enum_multi("xlxtmp", $row, $xlxtmp_vals, 4, array(), 1); + + // xlxgrd[0-3] enum('NORMAL','ENGSAMP') + print_enum_multi("xlxgrd", $row, $xlxgrd_vals, 4, array(), 1); + + // cputyp enum('MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)') + print_enum("cputyp", $row, $cputyp_vals); + + // cpuspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ') + print_enum_select("cpuspd", $row, $clk_vals); + + // cpmspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ') + print_enum_select("cpmspd", $row, $clk_vals); + + // busspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ') + print_enum_select("busspd", $row, $clk_vals); + + // hstype enum('AMCC-S2064A') + print_enum("hstype", $row, $hstype_vals); + + // hschin enum('0','1','2','3','4') + print_enum("hschin", $row, $hschin_vals); + + // hschout enum('0','1','2','3','4') + print_enum("hschout", $row, $hschout_vals); + + end_table(); + + echo "<p>\n"; + echo "<center><b>"; + echo "<font color=#ff0000>WARNING: NO UNDO ON DELETE!</font>"; + echo "<br></br>\n"; + echo "<tt>[ <a href=\"dodelete.php?serno=$serno\">delete</a> ]</tt>"; + echo "</b></center>\n"; + echo "</p>\n"; +?> +<p> +<table align=center width="100%"> +<tr> + <td align=center> + <input type=submit value=Edit> + </td> + <td> + + </td> + <td align=center> + <input type=reset value=Reset> + </td> + <td> + + </td> + <td align=center> + <a href="index.php">Back to Start</a> + </td> +</tr> +</table> +</p> +</form> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/edlog.php b/qemu/roms/u-boot/tools/bddb/edlog.php new file mode 100644 index 000000000..8befd35b9 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/edlog.php @@ -0,0 +1,86 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // edit page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - Edit Board Log Entry"); + + if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '') + die("serial number not specified!"); + $serno=intval($_REQUEST['serno']); + + if (!isset($_REQUEST['logno']) || $_REQUEST['logno'] == '') + die("log number not specified!"); + $logno=intval($_REQUEST['logno']); + + $pserno = sprintf("%010d", $serno); + $plogno = sprintf("%010d", $logno); + + echo "<center><b><font size=+2>"; + echo "Board Serial Number: $pserno, Log Number: $plogno"; + echo "</font></b></center>\n"; + +?> +<p> +<form action=doedlog.php method=POST> +<?php + echo "<input type=hidden name=serno value=$serno>\n"; + echo "<input type=hidden name=logno value=$logno>\n"; + + $r=mysql_query("select * from log where serno=$serno and logno=$logno"); + $row=mysql_fetch_array($r); + if(!$row) + die("no record of log entry with serial number '$serno' " . + "and log number '$logno' in database"); + + begin_table(3); + + // date date + print_field("date", $row); + + // who char(20) + print_field("who", $row); + + // details text + print_field_multiline("details", $row, 60, 10, 'text_filter'); + + end_table(); + + echo "<p>\n"; + echo "<center><b>"; + echo "<font color=#ff0000>WARNING: NO UNDO ON DELETE!</font>"; + echo "<br></br>\n"; + echo "<tt>[ <a href=\"dodellog.php?serno=$serno&logno=$logno\">delete</a> ]</tt>"; + echo "</b></center>\n"; + echo "</p>\n"; +?> +<p> +<table align=center width="100%"> +<tr> + <td align=center> + <input type=submit value=Edit> + </td> + <td> + + </td> + <td align=center> + <input type=reset value=Reset> + </td> + <td> + + </td> + <td align=center> + <a href="index.php">Back to Start</a> + </td> +</tr> +</table> +</p> +</form> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/execute.php b/qemu/roms/u-boot/tools/bddb/execute.php new file mode 100644 index 000000000..0b62882d7 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/execute.php @@ -0,0 +1,33 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + $serno=isset($_REQUEST['serno'])?$_REQUEST['serno']:''; + + $submit=isset($_REQUEST['submit'])?$_REQUEST['submit']:"[NOT SET]"; + + switch ($submit) { + + case "New": + require("new.php"); + break; + + case "Edit": + require("edit.php"); + break; + + case "Browse": + require("browse.php"); + break; + + case "Log": + require("brlog.php"); + break; + + default: + require("badsubmit.php"); + break; + } +?> diff --git a/qemu/roms/u-boot/tools/bddb/index.php b/qemu/roms/u-boot/tools/bddb/index.php new file mode 100644 index 000000000..842aed55f --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/index.php @@ -0,0 +1,38 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + require("defs.php"); + pg_head("$bddb_label"); +?> +<font size="+4"> + <form action=execute.php method=POST> + <table width="100%" cellspacing=10 cellpadding=10> + <tr> + <td align=center> + <input type=submit name=submit value="New"></input> + </td> + <td align=center> + <input type=submit name=submit value="Edit"></input> + </td> + <td align=center> + <input type=submit name=submit value="Browse"></input> + </td> + <td align=center> + <input type=submit name=submit value="Log"></input> + </td> + </tr> + <tr> + <td align=center colspan=4> + <b>Serial Number:</b> + <input type=text name=serno size=10 maxsize=10 value=""></input> + </td> + </tr> + </table> + </form> +</font> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/new.php b/qemu/roms/u-boot/tools/bddb/new.php new file mode 100644 index 000000000..30323ff81 --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/new.php @@ -0,0 +1,120 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // edit page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - New Board Registration"); +?> +<form action=donew.php method=POST> +<p></p> +<?php + $serno=intval($serno); + // if a serial number was supplied, fetch the record + // and use its contents as defaults + if ($serno != 0) { + $r=mysql_query("select * from boards where serno=$serno"); + $row=mysql_fetch_array($r); + if(!$row)die("no record of serial number '$serno' in database"); + } + else + $row = array(); + + begin_table(5); + + // date date + print_field("date", array('date' => date("Y-m-d"))); + + // batch char(32) + print_field("batch", $row, 32); + + // type enum('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY') + print_enum("type", $row, $type_vals, 0); + + // rev tinyint(3) unsigned zerofill + print_field("rev", $row, 3, 'rev_filter'); + + // sdram[0-3] enum('32M','64M','128M','256M') + print_enum_multi("sdram", $row, $sdram_vals, 4, array(2)); + + // flash[0-3] enum('4M','8M','16M','32M','64M') + print_enum_multi("flash", $row, $flash_vals, 4, array(2)); + + // zbt[0-f] enum('512K','1M','2M','4M') + print_enum_multi("zbt", $row, $zbt_vals, 16, array(2, 2)); + + // xlxtyp[0-3] enum('XCV300E','XCV400E','XCV600E') + print_enum_multi("xlxtyp", $row, $xlxtyp_vals, 4, array(1), 1); + + // xlxspd[0-3] enum('6','7','8') + print_enum_multi("xlxspd", $row, $xlxspd_vals, 4, array(1), 1); + + // xlxtmp[0-3] enum('COM','IND') + print_enum_multi("xlxtmp", $row, $xlxtmp_vals, 4, array(1), 1); + + // xlxgrd[0-3] enum('NORMAL','ENGSAMP') + print_enum_multi("xlxgrd", $row, $xlxgrd_vals, 4, array(1), 1); + + // cputyp enum('MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)') + print_enum("cputyp", $row, $cputyp_vals, 1); + + // cpuspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ') + print_enum_select("cpuspd", $row, $clk_vals, 4); + + // cpmspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ') + print_enum_select("cpmspd", $row, $clk_vals, 4); + + // busspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ') + print_enum_select("busspd", $row, $clk_vals, 2); + + // hstype enum('AMCC-S2064A') + print_enum("hstype", $row, $hstype_vals, 1); + + // hschin enum('0','1','2','3','4') + print_enum("hschin", $row, $hschin_vals, 4); + + // hschout enum('0','1','2','3','4') + print_enum("hschout", $row, $hschout_vals, 4); + + end_table(); +?> +<p></p> +<table width="100%"> +<tr> + <td align=center colspan=3> + Allocate + <input type=text name=quant size=2 maxlength=2 value=" 1"> + board serial number(s) + </td> +</tr> +<tr> + <td align=center colspan=3> + <input type=checkbox name=geneths checked> + Generate Ethernet Address(es) + </td> +</tr> +<tr> + <td colspan=3> + + </td> +</tr> +<tr> + <td align=center> + <input type=submit value="Register Board"> + </td> + <td> + + </td> + <td align=center> + <input type=reset value="Reset Form Contents"> + </td> +</tr> +</table> +</form> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bddb/newlog.php b/qemu/roms/u-boot/tools/bddb/newlog.php new file mode 100644 index 000000000..609bb855c --- /dev/null +++ b/qemu/roms/u-boot/tools/bddb/newlog.php @@ -0,0 +1,54 @@ +<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?> +<?php + // (C) Copyright 2001 + // Murray Jensen <Murray.Jensen@csiro.au> + // CSIRO Manufacturing Science and Technology, Preston Lab + + // edit page (hymod_bddb / boards) + + require("defs.php"); + + pg_head("$bddb_label - New Log Entry"); + + if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '') + die("serial number not specified or invalid!"); + $serno=intval($_REQUEST['serno']); + + if (isset($_REQUEST['logno'])) { + $logno=$_REQUEST['logno']; + die("log number must not be specified when adding! ($logno)"); + } +?> +<form action=donewlog.php method=POST> +<p></p> +<?php + echo "<input type=hidden name=serno value=$serno>\n"; + + begin_table(3); + + // date date + print_field("date", array('date' => date("Y-m-d"))); + + // who char(20) + print_field("who", array()); + + // details text + print_field_multiline("details", array(), 60, 10, 'text_filter'); + + end_table(); +?> +<p></p> +<table width="100%"> +<tr> + <td align=center> + <input type=submit value="Add Log Entry"> + </td> + <td align=center> + <input type=reset value="Reset Form Contents"> + </td> +</tr> +</table> +</form> +<?php + pg_foot(); +?> diff --git a/qemu/roms/u-boot/tools/bin2header.c b/qemu/roms/u-boot/tools/bin2header.c new file mode 100644 index 000000000..27a5b6aab --- /dev/null +++ b/qemu/roms/u-boot/tools/bin2header.c @@ -0,0 +1,40 @@ +/* bin2header.c - program to convert binary file into a C structure + * definition to be included in a header file. + * + * (C) Copyright 2008 by Harald Welte <laforge@openmoko.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <stdlib.h> +#include <stdio.h> + +int main(int argc, char **argv) +{ + if (argc < 2) { + fprintf(stderr, "%s needs one argument: the structure name\n", + argv[0]); + exit(1); + } + + printf("/* bin2header output - automatically generated */\n"); + printf("unsigned char %s[] = {\n", argv[1]); + + while (1) { + int i, nread; + unsigned char buf[10]; + nread = read(0, buf, sizeof(buf)); + if (nread <= 0) + break; + + printf("\t"); + for (i = 0; i < nread - 1; i++) + printf("0x%02x, ", buf[i]); + + printf("0x%02x,\n", buf[nread-1]); + } + + printf("};\n"); + + exit(0); +} diff --git a/qemu/roms/u-boot/tools/bmp_logo.c b/qemu/roms/u-boot/tools/bmp_logo.c new file mode 100644 index 000000000..2247adcc8 --- /dev/null +++ b/qemu/roms/u-boot/tools/bmp_logo.c @@ -0,0 +1,203 @@ +#include "compiler.h" + +enum { + MODE_GEN_INFO, + MODE_GEN_DATA +}; + +typedef struct bitmap_s { /* bitmap description */ + uint16_t width; + uint16_t height; + uint8_t palette[256*3]; + uint8_t *data; +} bitmap_t; + +#define DEFAULT_CMAP_SIZE 16 /* size of default color map */ + +void usage(const char *prog) +{ + fprintf(stderr, "Usage: %s [--gen-info|--gen-data] file\n", prog); +} + +/* + * Neutralize little endians. + */ +uint16_t le_short(uint16_t x) +{ + uint16_t val; + uint8_t *p = (uint8_t *)(&x); + + val = (*p++ & 0xff) << 0; + val |= (*p & 0xff) << 8; + + return val; +} + +void skip_bytes (FILE *fp, int n) +{ + while (n-- > 0) + fgetc (fp); +} + +__attribute__ ((__noreturn__)) +int error (char * msg, FILE *fp) +{ + fprintf (stderr, "ERROR: %s\n", msg); + + fclose (fp); + + exit (EXIT_FAILURE); +} + +void gen_info(bitmap_t *b, uint16_t n_colors) +{ + printf("/*\n" + " * Automatically generated by \"tools/bmp_logo\"\n" + " *\n" + " * DO NOT EDIT\n" + " *\n" + " */\n\n\n" + "#ifndef __BMP_LOGO_H__\n" + "#define __BMP_LOGO_H__\n\n" + "#define BMP_LOGO_WIDTH\t\t%d\n" + "#define BMP_LOGO_HEIGHT\t\t%d\n" + "#define BMP_LOGO_COLORS\t\t%d\n" + "#define BMP_LOGO_OFFSET\t\t%d\n\n" + "extern unsigned short bmp_logo_palette[];\n" + "extern unsigned char bmp_logo_bitmap[];\n\n" + "#endif /* __BMP_LOGO_H__ */\n", + b->width, b->height, n_colors, + DEFAULT_CMAP_SIZE); +} + +int main (int argc, char *argv[]) +{ + int mode, i, x; + FILE *fp; + bitmap_t bmp; + bitmap_t *b = &bmp; + uint16_t data_offset, n_colors; + + if (argc < 3) { + usage(argv[0]); + exit (EXIT_FAILURE); + } + + if (!strcmp(argv[1], "--gen-info")) + mode = MODE_GEN_INFO; + else if (!strcmp(argv[1], "--gen-data")) + mode = MODE_GEN_DATA; + else { + usage(argv[0]); + exit(EXIT_FAILURE); + } + + fp = fopen(argv[2], "rb"); + if (!fp) { + perror(argv[2]); + exit (EXIT_FAILURE); + } + + if (fgetc (fp) != 'B' || fgetc (fp) != 'M') + error ("Input file is not a bitmap", fp); + + /* + * read width and height of the image, and the number of colors used; + * ignore the rest + */ + skip_bytes (fp, 8); + if (fread (&data_offset, sizeof (uint16_t), 1, fp) != 1) + error ("Couldn't read bitmap data offset", fp); + skip_bytes (fp, 6); + if (fread (&b->width, sizeof (uint16_t), 1, fp) != 1) + error ("Couldn't read bitmap width", fp); + skip_bytes (fp, 2); + if (fread (&b->height, sizeof (uint16_t), 1, fp) != 1) + error ("Couldn't read bitmap height", fp); + skip_bytes (fp, 22); + if (fread (&n_colors, sizeof (uint16_t), 1, fp) != 1) + error ("Couldn't read bitmap colors", fp); + skip_bytes (fp, 6); + + /* + * Repair endianess. + */ + data_offset = le_short(data_offset); + b->width = le_short(b->width); + b->height = le_short(b->height); + n_colors = le_short(n_colors); + + /* assume we are working with an 8-bit file */ + if ((n_colors == 0) || (n_colors > 256 - DEFAULT_CMAP_SIZE)) { + /* reserve DEFAULT_CMAP_SIZE color map entries for default map */ + n_colors = 256 - DEFAULT_CMAP_SIZE; + } + + if (mode == MODE_GEN_INFO) { + gen_info(b, n_colors); + goto out; + } + + printf("/*\n" + " * Automatically generated by \"tools/bmp_logo\"\n" + " *\n" + " * DO NOT EDIT\n" + " *\n" + " */\n\n\n" + "#ifndef __BMP_LOGO_DATA_H__\n" + "#define __BMP_LOGO_DATA_H__\n\n"); + + /* allocate memory */ + if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL) + error ("Error allocating memory for file", fp); + + /* read and print the palette information */ + printf("unsigned short bmp_logo_palette[] = {\n"); + + for (i=0; i<n_colors; ++i) { + b->palette[(int)(i*3+2)] = fgetc(fp); + b->palette[(int)(i*3+1)] = fgetc(fp); + b->palette[(int)(i*3+0)] = fgetc(fp); + x=fgetc(fp); + + printf ("%s0x0%X%X%X,%s", + ((i%8) == 0) ? "\t" : " ", + (b->palette[(int)(i*3+0)] >> 4) & 0x0F, + (b->palette[(int)(i*3+1)] >> 4) & 0x0F, + (b->palette[(int)(i*3+2)] >> 4) & 0x0F, + ((i%8) == 7) ? "\n" : "" + ); + } + + /* seek to offset indicated by file header */ + fseek(fp, (long)data_offset, SEEK_SET); + + /* read the bitmap; leave room for default color map */ + printf ("\n"); + printf ("};\n"); + printf ("\n"); + printf("unsigned char bmp_logo_bitmap[] = {\n"); + for (i=(b->height-1)*b->width; i>=0; i-=b->width) { + for (x = 0; x < b->width; x++) { + b->data[i + x] = (uint8_t) fgetc(fp) + + DEFAULT_CMAP_SIZE; + } + } + + for (i=0; i<(b->height*b->width); ++i) { + if ((i%8) == 0) + putchar ('\t'); + printf ("0x%02X,%c", + b->data[i], + ((i%8) == 7) ? '\n' : ' ' + ); + } + printf ("\n" + "};\n\n" + "#endif /* __BMP_LOGO_DATA_H__ */\n" + ); + +out: + fclose(fp); + return 0; +} diff --git a/qemu/roms/u-boot/tools/buildman/.gitignore b/qemu/roms/u-boot/tools/buildman/.gitignore new file mode 100644 index 000000000..0d20b6487 --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/qemu/roms/u-boot/tools/buildman/README b/qemu/roms/u-boot/tools/buildman/README new file mode 100644 index 000000000..c30c1d411 --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/README @@ -0,0 +1,690 @@ +# Copyright (c) 2013 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +What is this? +============= + +This tool handles building U-Boot to check that you have not broken it +with your patch series. It can build each individual commit and report +which boards fail on which commits, and which errors come up. It aims +to make full use of multi-processor machines. + +A key feature of buildman is its output summary, which allows warnings, +errors or image size increases in a particular commit or board to be +quickly identified and the offending commit pinpointed. This can be a big +help for anyone working with >10 patches at a time. + + +Caveats +======= + +Buildman is still in its infancy. It is already a very useful tool, but +expect to find problems and send patches. + +Buildman can be stopped and restarted, in which case it will continue +where it left off. This should happen cleanly and without side-effects. +If not, it is a bug, for which a patch would be welcome. + +Buildman gets so tied up in its work that it can ignore the outside world. +You may need to press Ctrl-C several times to quit it. Also it will print +out various exceptions when stopped. + + +Theory of Operation +=================== + +(please read this section in full twice or you will be perpetually confused) + +Buildman is a builder. It is not make, although it runs make. It does not +produce any useful output on the terminal while building, except for +progress information. All the output (errors, warnings and binaries if you +are ask for them) is stored in output directories, which you can look at +while the build is progressing, or when it is finished. + +Buildman produces a concise summary of which boards succeeded and failed. +It shows which commit introduced which board failure using a simple +red/green colour coding. Full error information can be requested, in which +case it is de-duped and displayed against the commit that introduced the +error. An example workflow is below. + +Buildman stores image size information and can report changes in image size +from commit to commit. An example of this is below. + +Buildman starts multiple threads, and each thread builds for one board at +a time. A thread starts at the first commit, configures the source for your +board and builds it. Then it checks out the next commit and does an +incremental build. Eventually the thread reaches the last commit and stops. +If errors or warnings are found along the way, the thread will reconfigure +after every commit, and your build will be very slow. This is because a +file that produces just a warning would not normally be rebuilt in an +incremental build. + +Buildman works in an entirely separate place from your U-Boot repository. +It creates a separate working directory for each thread, and puts the +output files in the working directory, organised by commit name and board +name, in a two-level hierarchy. + +Buildman is invoked in your U-Boot directory, the one with the .git +directory. It clones this repository into a copy for each thread, and the +threads do not affect the state of your git repository. Any checkouts done +by the thread affect only the working directory for that thread. + +Buildman automatically selects the correct toolchain for each board. You +must supply suitable toolchains, but buildman takes care of selecting the +right one. + +Buildman always builds a branch, and always builds the upstream commit as +well, for comparison. It cannot build individual commits at present, unless +(maybe) you point it at an empty branch. Put all your commits in a branch, +set the branch's upstream to a valid value, and all will be well. Otherwise +buildman will perform random actions. Use -n to check what the random +actions might be. + +Buildman is optimised for building many commits at once, for many boards. +On multi-core machines, Buildman is fast because it uses most of the +available CPU power. When it gets to the end, or if you are building just +a few commits or boards, it will be pretty slow. As a tip, if you don't +plan to use your machine for anything else, you can use -T to increase the +number of threads beyond the default. + +Buildman lets you build all boards, or a subset. Specify the subset by passing +command-line arguments that list the desired board name, architecture name, +SOC name, or anything else in the boards.cfg file. Multiple arguments are +allowed. Each argument will be interpreted as a regular expression, so +behaviour is a superset of exact or substring matching. Examples are: + +* 'tegra20' All boards with a Tegra20 SoC +* 'tegra' All boards with any Tegra Soc (Tegra20, Tegra30, Tegra114...) +* '^tegra[23]0$' All boards with either Tegra20 or Tegra30 SoC +* 'powerpc' All PowerPC boards + +Buildman does not store intermediate object files. It optionally copies +the binary output into a directory when a build is successful. Size +information is always recorded. It needs a fair bit of disk space to work, +typically 250MB per thread. + + +Setting up +========== + +1. Get the U-Boot source. You probably already have it, but if not these +steps should get you started with a repo and some commits for testing. + +$ cd /path/to/u-boot +$ git clone git://git.denx.de/u-boot.git . +$ git checkout -b my-branch origin/master +$ # Add some commits to the branch, reading for testing + +2. Create ~/.buildman to tell buildman where to find tool chains. As an +example: + +# Buildman settings file + +[toolchain] +root: / +rest: /toolchains/* +eldk: /opt/eldk-4.2 + +[toolchain-alias] +x86: i386 +blackfin: bfin +sh: sh4 +nds32: nds32le +openrisc: or32 + + +This selects the available toolchain paths. Add the base directory for +each of your toolchains here. Buildman will search inside these directories +and also in any '/usr' and '/usr/bin' subdirectories. + +Make sure the tags (here root: rest: and eldk:) are unique. + +The toolchain-alias section indicates that the i386 toolchain should be used +to build x86 commits. + + +2. Check the available toolchains + +Run this check to make sure that you have a toolchain for every architecture. + +$ ./tools/buildman/buildman --list-tool-chains +Scanning for tool chains + - scanning path '/' + - looking in '/.' + - looking in '/bin' + - looking in '/usr/bin' + - found '/usr/bin/gcc' +Tool chain test: OK + - found '/usr/bin/c89-gcc' +Tool chain test: OK + - found '/usr/bin/c99-gcc' +Tool chain test: OK + - found '/usr/bin/x86_64-linux-gnu-gcc' +Tool chain test: OK + - scanning path '/toolchains/powerpc-linux' + - looking in '/toolchains/powerpc-linux/.' + - looking in '/toolchains/powerpc-linux/bin' + - found '/toolchains/powerpc-linux/bin/powerpc-linux-gcc' +Tool chain test: OK + - looking in '/toolchains/powerpc-linux/usr/bin' + - scanning path '/toolchains/nds32le-linux-glibc-v1f' + - looking in '/toolchains/nds32le-linux-glibc-v1f/.' + - looking in '/toolchains/nds32le-linux-glibc-v1f/bin' + - found '/toolchains/nds32le-linux-glibc-v1f/bin/nds32le-linux-gcc' +Tool chain test: OK + - looking in '/toolchains/nds32le-linux-glibc-v1f/usr/bin' + - scanning path '/toolchains/nios2' + - looking in '/toolchains/nios2/.' + - looking in '/toolchains/nios2/bin' + - found '/toolchains/nios2/bin/nios2-linux-gcc' +Tool chain test: OK + - found '/toolchains/nios2/bin/nios2-linux-uclibc-gcc' +Tool chain test: OK + - looking in '/toolchains/nios2/usr/bin' + - found '/toolchains/nios2/usr/bin/nios2-linux-gcc' +Tool chain test: OK + - found '/toolchains/nios2/usr/bin/nios2-linux-uclibc-gcc' +Tool chain test: OK + - scanning path '/toolchains/microblaze-unknown-linux-gnu' + - looking in '/toolchains/microblaze-unknown-linux-gnu/.' + - looking in '/toolchains/microblaze-unknown-linux-gnu/bin' + - found '/toolchains/microblaze-unknown-linux-gnu/bin/microblaze-unknown-linux-gnu-gcc' +Tool chain test: OK + - found '/toolchains/microblaze-unknown-linux-gnu/bin/mb-linux-gcc' +Tool chain test: OK + - looking in '/toolchains/microblaze-unknown-linux-gnu/usr/bin' + - scanning path '/toolchains/mips-linux' + - looking in '/toolchains/mips-linux/.' + - looking in '/toolchains/mips-linux/bin' + - found '/toolchains/mips-linux/bin/mips-linux-gcc' +Tool chain test: OK + - looking in '/toolchains/mips-linux/usr/bin' + - scanning path '/toolchains/old' + - looking in '/toolchains/old/.' + - looking in '/toolchains/old/bin' + - looking in '/toolchains/old/usr/bin' + - scanning path '/toolchains/i386-linux' + - looking in '/toolchains/i386-linux/.' + - looking in '/toolchains/i386-linux/bin' + - found '/toolchains/i386-linux/bin/i386-linux-gcc' +Tool chain test: OK + - looking in '/toolchains/i386-linux/usr/bin' + - scanning path '/toolchains/bfin-uclinux' + - looking in '/toolchains/bfin-uclinux/.' + - looking in '/toolchains/bfin-uclinux/bin' + - found '/toolchains/bfin-uclinux/bin/bfin-uclinux-gcc' +Tool chain test: OK + - looking in '/toolchains/bfin-uclinux/usr/bin' + - scanning path '/toolchains/sparc-elf' + - looking in '/toolchains/sparc-elf/.' + - looking in '/toolchains/sparc-elf/bin' + - found '/toolchains/sparc-elf/bin/sparc-elf-gcc' +Tool chain test: OK + - looking in '/toolchains/sparc-elf/usr/bin' + - scanning path '/toolchains/arm-2010q1' + - looking in '/toolchains/arm-2010q1/.' + - looking in '/toolchains/arm-2010q1/bin' + - found '/toolchains/arm-2010q1/bin/arm-none-linux-gnueabi-gcc' +Tool chain test: OK + - looking in '/toolchains/arm-2010q1/usr/bin' + - scanning path '/toolchains/from' + - looking in '/toolchains/from/.' + - looking in '/toolchains/from/bin' + - looking in '/toolchains/from/usr/bin' + - scanning path '/toolchains/sh4-gentoo-linux-gnu' + - looking in '/toolchains/sh4-gentoo-linux-gnu/.' + - looking in '/toolchains/sh4-gentoo-linux-gnu/bin' + - found '/toolchains/sh4-gentoo-linux-gnu/bin/sh4-gentoo-linux-gnu-gcc' +Tool chain test: OK + - looking in '/toolchains/sh4-gentoo-linux-gnu/usr/bin' + - scanning path '/toolchains/avr32-linux' + - looking in '/toolchains/avr32-linux/.' + - looking in '/toolchains/avr32-linux/bin' + - found '/toolchains/avr32-linux/bin/avr32-gcc' +Tool chain test: OK + - looking in '/toolchains/avr32-linux/usr/bin' + - scanning path '/toolchains/m68k-linux' + - looking in '/toolchains/m68k-linux/.' + - looking in '/toolchains/m68k-linux/bin' + - found '/toolchains/m68k-linux/bin/m68k-linux-gcc' +Tool chain test: OK + - looking in '/toolchains/m68k-linux/usr/bin' +List of available toolchains (17): +arm : /toolchains/arm-2010q1/bin/arm-none-linux-gnueabi-gcc +avr32 : /toolchains/avr32-linux/bin/avr32-gcc +bfin : /toolchains/bfin-uclinux/bin/bfin-uclinux-gcc +c89 : /usr/bin/c89-gcc +c99 : /usr/bin/c99-gcc +i386 : /toolchains/i386-linux/bin/i386-linux-gcc +m68k : /toolchains/m68k-linux/bin/m68k-linux-gcc +mb : /toolchains/microblaze-unknown-linux-gnu/bin/mb-linux-gcc +microblaze: /toolchains/microblaze-unknown-linux-gnu/bin/microblaze-unknown-linux-gnu-gcc +mips : /toolchains/mips-linux/bin/mips-linux-gcc +nds32le : /toolchains/nds32le-linux-glibc-v1f/bin/nds32le-linux-gcc +nios2 : /toolchains/nios2/bin/nios2-linux-gcc +powerpc : /toolchains/powerpc-linux/bin/powerpc-linux-gcc +sandbox : /usr/bin/gcc +sh4 : /toolchains/sh4-gentoo-linux-gnu/bin/sh4-gentoo-linux-gnu-gcc +sparc : /toolchains/sparc-elf/bin/sparc-elf-gcc +x86_64 : /usr/bin/x86_64-linux-gnu-gcc + + +You can see that everything is covered, even some strange ones that won't +be used (c88 and c99). This is a feature. + + +How to run it +============= + +First do a dry run using the -n flag: (replace <branch> with a real, local +branch with a valid upstream) + +$ ./tools/buildman/buildman -b <branch> -n + +If it can't detect the upstream branch, try checking out the branch, and +doing something like 'git branch --set-upstream <branch> upstream/master' +or something similar. + +As an exmmple: + +Dry run, so not doing much. But I would do this: + +Building 18 commits for 1059 boards (4 threads, 1 job per thread) +Build directory: ../lcd9b + 5bb3505 Merge branch 'master' of git://git.denx.de/u-boot-arm + c18f1b4 tegra: Use const for pinmux_config_pingroup/table() + 2f043ae tegra: Add display support to funcmux + e349900 tegra: fdt: Add pwm binding and node + 424a5f0 tegra: fdt: Add LCD definitions for Tegra + 0636ccf tegra: Add support for PWM + a994fe7 tegra: Add SOC support for display/lcd + fcd7350 tegra: Add LCD driver + 4d46e9d tegra: Add LCD support to Nvidia boards + 991bd48 arm: Add control over cachability of memory regions + 54e8019 lcd: Add CONFIG_LCD_ALIGNMENT to select frame buffer alignment + d92aff7 lcd: Add support for flushing LCD fb from dcache after update + dbd0677 tegra: Align LCD frame buffer to section boundary + 0cff9b8 tegra: Support control of cache settings for LCD + 9c56900 tegra: fdt: Add LCD definitions for Seaboard + 5cc29db lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console + cac5a23 tegra: Enable display/lcd support on Seaboard + 49ff541 wip + +Total boards to build for each commit: 1059 + +This shows that it will build all 1059 boards, using 4 threads (because +we have a 4-core CPU). Each thread will run with -j1, meaning that each +make job will use a single CPU. The list of commits to be built helps you +confirm that things look about right. Notice that buildman has chosen a +'base' directory for you, immediately above your source tree. + +Buildman works entirely inside the base directory, here ../lcd9b, +creating a working directory for each thread, and creating output +directories for each commit and board. + + +Suggested Workflow +================== + +To run the build for real, take off the -n: + +$ ./tools/buildman/buildman -b <branch> + +Buildman will set up some working directories, and get started. After a +minute or so it will settle down to a steady pace, with a display like this: + +Building 18 commits for 1059 boards (4 threads, 1 job per thread) + 528 36 124 /19062 1:13:30 : SIMPC8313_SP + +This means that it is building 19062 board/commit combinations. So far it +has managed to succesfully build 528. Another 36 have built with warnings, +and 124 more didn't build at all. Buildman expects to complete the process +in an hour and 15 minutes. Use this time to buy a faster computer. + + +To find out how the build went, ask for a summary with -s. You can do this +either before the build completes (presumably in another terminal) or or +afterwards. Let's work through an example of how this is used: + +$ ./tools/buildman/buildman -b lcd9b -s +... +01: Merge branch 'master' of git://git.denx.de/u-boot-arm + powerpc: + galaxy5200_LOWBOOT +02: tegra: Use const for pinmux_config_pingroup/table() +03: tegra: Add display support to funcmux +04: tegra: fdt: Add pwm binding and node +05: tegra: fdt: Add LCD definitions for Tegra +06: tegra: Add support for PWM +07: tegra: Add SOC support for display/lcd +08: tegra: Add LCD driver +09: tegra: Add LCD support to Nvidia boards +10: arm: Add control over cachability of memory regions +11: lcd: Add CONFIG_LCD_ALIGNMENT to select frame buffer alignment +12: lcd: Add support for flushing LCD fb from dcache after update + arm: + lubbock +13: tegra: Align LCD frame buffer to section boundary +14: tegra: Support control of cache settings for LCD +15: tegra: fdt: Add LCD definitions for Seaboard +16: lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console +17: tegra: Enable display/lcd support on Seaboard +18: wip + +This shows which commits have succeeded and which have failed. In this case +the build is still in progress so many boards are not built yet (use -u to +see which ones). But still we can see a few failures. The galaxy5200_LOWBOOT +never builds correctly. This could be a problem with our toolchain, or it +could be a bug in the upstream. The good news is that we probably don't need +to blame our commits. The bad news is it isn't tested on that board. + +Commit 12 broke lubbock. That's what the '+ lubbock' means. The failure +is never fixed by a later commit, or you would see lubbock again, in green, +without the +. + +To see the actual error: + +$ ./tools/buildman/buildman -b <branch> -se lubbock +... +12: lcd: Add support for flushing LCD fb from dcache after update + arm: + lubbock ++common/libcommon.o: In function `lcd_sync': ++/u-boot/lcd9b/.bm-work/00/common/lcd.c:120: undefined reference to `flush_dcache_range' ++arm-none-linux-gnueabi-ld: BFD (Sourcery G++ Lite 2010q1-202) 2.19.51.20090709 assertion fail /scratch/julian/2010q1-release-linux-lite/obj/binutils-src-2010q1-202-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:12572 ++make: *** [/u-boot/lcd9b/.bm-work/00/build/u-boot] Error 139 +13: tegra: Align LCD frame buffer to section boundary +14: tegra: Support control of cache settings for LCD +15: tegra: fdt: Add LCD definitions for Seaboard +16: lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console +-/u-boot/lcd9b/.bm-work/00/common/lcd.c:120: undefined reference to `flush_dcache_range' ++/u-boot/lcd9b/.bm-work/00/common/lcd.c:125: undefined reference to `flush_dcache_range' +17: tegra: Enable display/lcd support on Seaboard +18: wip + +So the problem is in lcd.c, due to missing cache operations. This information +should be enough to work out what that commit is doing to break these +boards. (In this case pxa did not have cache operations defined). + +If you see error lines marked with - that means that the errors were fixed +by that commit. Sometimes commits can be in the wrong order, so that a +breakage is introduced for a few commits and fixed by later commits. This +shows up clearly with buildman. You can then reorder the commits and try +again. + +At commit 16, the error moves - you can see that the old error at line 120 +is fixed, but there is a new one at line 126. This is probably only because +we added some code and moved the broken line futher down the file. + +If many boards have the same error, then -e will display the error only +once. This makes the output as concise as possible. + +The full build output in this case is available in: + +../lcd9b/12_of_18_gd92aff7_lcd--Add-support-for/lubbock/ + + done: Indicates the build was done, and holds the return code from make. + This is 0 for a good build, typically 2 for a failure. + + err: Output from stderr, if any. Errors and warnings appear here. + + log: Output from stdout. Normally there isn't any since buildman runs + in silent mode for now. + + toolchain: Shows information about the toolchain used for the build. + + sizes: Shows image size information. + +It is possible to get the build output there also. Use the -k option for +this. In that case you will also see some output files, like: + + System.map toolchain u-boot u-boot.bin u-boot.map autoconf.mk + (also SPL versions u-boot-spl and u-boot-spl.bin if available) + + +Checking Image Sizes +==================== + +A key requirement for U-Boot is that you keep code/data size to a minimum. +Where a new feature increases this noticeably it should normally be put +behind a CONFIG flag so that boards can leave it off and keep the image +size more or less the same with each new release. + +To check the impact of your commits on image size, use -S. For example: + +$ ./tools/buildman/buildman -b us-x86 -sS +Summary of 10 commits for 1066 boards (4 threads, 1 job per thread) +01: MAKEALL: add support for per architecture toolchains +02: x86: Add function to get top of usable ram + x86: (for 1/3 boards) text -272.0 rodata +41.0 +03: x86: Add basic cache operations +04: x86: Permit bootstage and timer data to be used prior to relocation + x86: (for 1/3 boards) data +16.0 +05: x86: Add an __end symbol to signal the end of the U-Boot binary + x86: (for 1/3 boards) text +76.0 +06: x86: Rearrange the output input to remove BSS + x86: (for 1/3 boards) bss -2140.0 +07: x86: Support relocation of FDT on start-up + x86: + coreboot-x86 +08: x86: Add error checking to x86 relocation code +09: x86: Adjust link device tree include file +10: x86: Enable CONFIG_OF_CONTROL on coreboot + + +You can see that image size only changed on x86, which is good because this +series is not supposed to change any other board. From commit 7 onwards the +build fails so we don't get code size numbers. The numbers are fractional +because they are an average of all boards for that architecture. The +intention is to allow you to quickly find image size problems introduced by +your commits. + +Note that the 'text' region and 'rodata' are split out. You should add the +two together to get the total read-only size (reported as the first column +in the output from binutil's 'size' utility). + +A useful option is --step which lets you skip some commits. For example +--step 2 will show the image sizes for only every 2nd commit (so it will +compare the image sizes of the 1st, 3rd, 5th... commits). You can also use +--step 0 which will compare only the first and last commits. This is useful +for an overview of how your entire series affects code size. + +You can also use -d to see a detailed size breakdown for each board. This +list is sorted in order from largest growth to largest reduction. + +It is possible to go a little further with the -B option (--bloat). This +shows where U-Boot has bloted, breaking the size change down to the function +level. Example output is below: + +$ ./tools/buildman/buildman -b us-mem4 -sSdB +... +19: Roll crc32 into hash infrastructure + arm: (for 10/10 boards) all -143.4 bss +1.2 data -4.8 rodata -48.2 text -91.6 + paz00 : all +23 bss -4 rodata -29 text +56 + u-boot: add: 1/0, grow: 3/-2 bytes: 168/-104 (64) + function old new delta + hash_command 80 160 +80 + crc32_wd_buf - 56 +56 + ext4fs_read_file 540 568 +28 + insert_var_value_sub 688 692 +4 + run_list_real 1996 1992 -4 + do_mem_crc 168 68 -100 + trimslice : all -9 bss +16 rodata -29 text +4 + u-boot: add: 1/0, grow: 1/-3 bytes: 136/-124 (12) + function old new delta + hash_command 80 160 +80 + crc32_wd_buf - 56 +56 + ext4fs_iterate_dir 672 668 -4 + ext4fs_read_file 568 548 -20 + do_mem_crc 168 68 -100 + whistler : all -9 bss +16 rodata -29 text +4 + u-boot: add: 1/0, grow: 1/-3 bytes: 136/-124 (12) + function old new delta + hash_command 80 160 +80 + crc32_wd_buf - 56 +56 + ext4fs_iterate_dir 672 668 -4 + ext4fs_read_file 568 548 -20 + do_mem_crc 168 68 -100 + seaboard : all -9 bss -28 rodata -29 text +48 + u-boot: add: 1/0, grow: 3/-2 bytes: 160/-104 (56) + function old new delta + hash_command 80 160 +80 + crc32_wd_buf - 56 +56 + ext4fs_read_file 548 568 +20 + run_list_real 1996 2000 +4 + do_nandboot 760 756 -4 + do_mem_crc 168 68 -100 + colibri_t20_iris: all -9 rodata -29 text +20 + u-boot: add: 1/0, grow: 2/-3 bytes: 140/-112 (28) + function old new delta + hash_command 80 160 +80 + crc32_wd_buf - 56 +56 + read_abs_bbt 204 208 +4 + do_nandboot 760 756 -4 + ext4fs_read_file 576 568 -8 + do_mem_crc 168 68 -100 + ventana : all -37 bss -12 rodata -29 text +4 + u-boot: add: 1/0, grow: 1/-3 bytes: 136/-124 (12) + function old new delta + hash_command 80 160 +80 + crc32_wd_buf - 56 +56 + ext4fs_iterate_dir 672 668 -4 + ext4fs_read_file 568 548 -20 + do_mem_crc 168 68 -100 + harmony : all -37 bss -16 rodata -29 text +8 + u-boot: add: 1/0, grow: 2/-3 bytes: 140/-124 (16) + function old new delta + hash_command 80 160 +80 + crc32_wd_buf - 56 +56 + nand_write_oob_syndrome 428 432 +4 + ext4fs_iterate_dir 672 668 -4 + ext4fs_read_file 568 548 -20 + do_mem_crc 168 68 -100 + medcom-wide : all -417 bss +28 data -16 rodata -93 text -336 + u-boot: add: 1/-1, grow: 1/-2 bytes: 88/-376 (-288) + function old new delta + crc32_wd_buf - 56 +56 + do_fat_read_at 2872 2904 +32 + hash_algo 16 - -16 + do_mem_crc 168 68 -100 + hash_command 420 160 -260 + tec : all -449 bss -4 data -16 rodata -93 text -336 + u-boot: add: 1/-1, grow: 1/-2 bytes: 88/-376 (-288) + function old new delta + crc32_wd_buf - 56 +56 + do_fat_read_at 2872 2904 +32 + hash_algo 16 - -16 + do_mem_crc 168 68 -100 + hash_command 420 160 -260 + plutux : all -481 bss +16 data -16 rodata -93 text -388 + u-boot: add: 1/-1, grow: 1/-3 bytes: 68/-408 (-340) + function old new delta + crc32_wd_buf - 56 +56 + do_load_serial_bin 1688 1700 +12 + hash_algo 16 - -16 + do_fat_read_at 2904 2872 -32 + do_mem_crc 168 68 -100 + hash_command 420 160 -260 + powerpc: (for 5/5 boards) all +37.4 data -3.2 rodata -41.8 text +82.4 + MPC8610HPCD : all +55 rodata -29 text +84 + u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80) + function old new delta + hash_command - 176 +176 + do_mem_crc 184 88 -96 + MPC8641HPCN : all +55 rodata -29 text +84 + u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80) + function old new delta + hash_command - 176 +176 + do_mem_crc 184 88 -96 + MPC8641HPCN_36BIT: all +55 rodata -29 text +84 + u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80) + function old new delta + hash_command - 176 +176 + do_mem_crc 184 88 -96 + sbc8641d : all +55 rodata -29 text +84 + u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80) + function old new delta + hash_command - 176 +176 + do_mem_crc 184 88 -96 + xpedite517x : all -33 data -16 rodata -93 text +76 + u-boot: add: 1/-1, grow: 0/-1 bytes: 176/-112 (64) + function old new delta + hash_command - 176 +176 + hash_algo 16 - -16 + do_mem_crc 184 88 -96 +... + + +This shows that commit 19 has increased text size for arm (although only one +board was built) and by 96 bytes for powerpc. This increase was offset in both +cases by reductions in rodata and data/bss. + +Shown below the summary lines is the sizes for each board. Below each board +is the sizes for each function. This information starts with: + + add - number of functions added / removed + grow - number of functions which grew / shrunk + bytes - number of bytes of code added to / removed from all functions, + plus the total byte change in brackets + +The change seems to be that hash_command() has increased by more than the +do_mem_crc() function has decreased. The function sizes typically add up to +roughly the text area size, but note that every read-only section except +rodata is included in 'text', so the function total does not exactly +correspond. + +It is common when refactoring code for the rodata to decrease as the text size +increases, and vice versa. + + +Providing 'make' flags +====================== + +U-Boot's build system supports a few flags (such as BUILD_TAG) which affect +the build product. These flags can be specified in the buildman settings +file. They can also be useful when building U-Boot against other open source +software. + +[make-flags] +at91-boards=ENABLE_AT91_TEST=1 +snapper9260=${at91-boards} BUILD_TAG=442 +snapper9g45=${at91-boards} BUILD_TAG=443 + +This will use 'make ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260 +and 'make ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. A special +variable ${target} is available to access the target name (snapper9260 and +snapper9g20 in this case). Variables are resolved recursively. + +It is expected that any variables added are dealt with in U-Boot's +config.mk file and documented in the README. + + +Other options +============= + +Buildman has various other command line options. Try --help to see them. + + +TODO +==== + +This has mostly be written in my spare time as a response to my difficulties +in testing large series of patches. Apart from tidying up there is quite a +bit of scope for improvement. Things like better error diffs, easier access +to log files, error display while building. Also it would be nice it buildman +could 'hunt' for problems, perhaps by building a few boards for each arch, +or checking commits for changed files and building only boards which use +those files. + + +Credits +======= + +Thanks to Grant Grundler <grundler@chromium.org> for his ideas for improving +the build speed by building all commits for a board instead of the other +way around. + + +Simon Glass +sjg@chromium.org +Halloween 2012 +Updated 12-12-12 +Updated 23-02-13 diff --git a/qemu/roms/u-boot/tools/buildman/board.py b/qemu/roms/u-boot/tools/buildman/board.py new file mode 100644 index 000000000..5172a473e --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/board.py @@ -0,0 +1,164 @@ +# Copyright (c) 2012 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import re + +class Board: + """A particular board that we can build""" + def __init__(self, status, arch, cpu, soc, vendor, board_name, target, options): + """Create a new board type. + + Args: + status: define whether the board is 'Active' or 'Orphaned' + arch: Architecture name (e.g. arm) + cpu: Cpu name (e.g. arm1136) + soc: Name of SOC, or '' if none (e.g. mx31) + vendor: Name of vendor (e.g. armltd) + board_name: Name of board (e.g. integrator) + target: Target name (use make <target>_config to configure) + options: board-specific options (e.g. integratorcp:CM1136) + """ + self.target = target + self.arch = arch + self.cpu = cpu + self.board_name = board_name + self.vendor = vendor + self.soc = soc + self.props = [self.target, self.arch, self.cpu, self.board_name, + self.vendor, self.soc] + self.options = options + self.build_it = False + + +class Boards: + """Manage a list of boards.""" + def __init__(self): + # Use a simple list here, sinc OrderedDict requires Python 2.7 + self._boards = [] + + def AddBoard(self, board): + """Add a new board to the list. + + The board's target member must not already exist in the board list. + + Args: + board: board to add + """ + self._boards.append(board) + + def ReadBoards(self, fname): + """Read a list of boards from a board file. + + Create a board object for each and add it to our _boards list. + + Args: + fname: Filename of boards.cfg file + """ + with open(fname, 'r') as fd: + for line in fd: + if line[0] == '#': + continue + fields = line.split() + if not fields: + continue + for upto in range(len(fields)): + if fields[upto] == '-': + fields[upto] = '' + while len(fields) < 8: + fields.append('') + if len(fields) > 8: + fields = fields[:8] + + board = Board(*fields) + self.AddBoard(board) + + + def GetList(self): + """Return a list of available boards. + + Returns: + List of Board objects + """ + return self._boards + + def GetDict(self): + """Build a dictionary containing all the boards. + + Returns: + Dictionary: + key is board.target + value is board + """ + board_dict = {} + for board in self._boards: + board_dict[board.target] = board + return board_dict + + def GetSelectedDict(self): + """Return a dictionary containing the selected boards + + Returns: + List of Board objects that are marked selected + """ + board_dict = {} + for board in self._boards: + if board.build_it: + board_dict[board.target] = board + return board_dict + + def GetSelected(self): + """Return a list of selected boards + + Returns: + List of Board objects that are marked selected + """ + return [board for board in self._boards if board.build_it] + + def GetSelectedNames(self): + """Return a list of selected boards + + Returns: + List of board names that are marked selected + """ + return [board.target for board in self._boards if board.build_it] + + def SelectBoards(self, args): + """Mark boards selected based on args + + Args: + List of strings specifying boards to include, either named, or + by their target, architecture, cpu, vendor or soc. If empty, all + boards are selected. + + Returns: + Dictionary which holds the number of boards which were selected + due to each argument, arranged by argument. + """ + result = {} + argres = {} + for arg in args: + result[arg] = 0 + argres[arg] = re.compile(arg) + result['all'] = 0 + + for board in self._boards: + if args: + for arg in args: + argre = argres[arg] + match = False + for prop in board.props: + match = argre.match(prop) + if match: + break + if match: + if not board.build_it: + board.build_it = True + result[arg] += 1 + result['all'] += 1 + else: + board.build_it = True + result['all'] += 1 + + return result diff --git a/qemu/roms/u-boot/tools/buildman/bsettings.py b/qemu/roms/u-boot/tools/buildman/bsettings.py new file mode 100644 index 000000000..916479866 --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/bsettings.py @@ -0,0 +1,41 @@ +# Copyright (c) 2012 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import ConfigParser +import os + + +def Setup(fname=''): + """Set up the buildman settings module by reading config files + + Args: + config_fname: Config filename to read ('' for default) + """ + global settings + global config_fname + + settings = ConfigParser.SafeConfigParser() + config_fname = fname + if config_fname == '': + config_fname = '%s/.buildman' % os.getenv('HOME') + if config_fname: + settings.read(config_fname) + +def GetItems(section): + """Get the items from a section of the config. + + Args: + section: name of section to retrieve + + Returns: + List of (name, value) tuples for the section + """ + try: + return settings.items(section) + except ConfigParser.NoSectionError as e: + print e + return [] + except: + raise diff --git a/qemu/roms/u-boot/tools/buildman/builder.py b/qemu/roms/u-boot/tools/buildman/builder.py new file mode 100644 index 000000000..4a2d753c2 --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/builder.py @@ -0,0 +1,1430 @@ +# Copyright (c) 2013 The Chromium OS Authors. +# +# Bloat-o-meter code used here Copyright 2004 Matt Mackall <mpm@selenic.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import collections +import errno +from datetime import datetime, timedelta +import glob +import os +import re +import Queue +import shutil +import string +import sys +import threading +import time + +import command +import gitutil +import terminal +import toolchain + + +""" +Theory of Operation + +Please see README for user documentation, and you should be familiar with +that before trying to make sense of this. + +Buildman works by keeping the machine as busy as possible, building different +commits for different boards on multiple CPUs at once. + +The source repo (self.git_dir) contains all the commits to be built. Each +thread works on a single board at a time. It checks out the first commit, +configures it for that board, then builds it. Then it checks out the next +commit and builds it (typically without re-configuring). When it runs out +of commits, it gets another job from the builder and starts again with that +board. + +Clearly the builder threads could work either way - they could check out a +commit and then built it for all boards. Using separate directories for each +commit/board pair they could leave their build product around afterwards +also. + +The intent behind building a single board for multiple commits, is to make +use of incremental builds. Since each commit is built incrementally from +the previous one, builds are faster. Reconfiguring for a different board +removes all intermediate object files. + +Many threads can be working at once, but each has its own working directory. +When a thread finishes a build, it puts the output files into a result +directory. + +The base directory used by buildman is normally '../<branch>', i.e. +a directory higher than the source repository and named after the branch +being built. + +Within the base directory, we have one subdirectory for each commit. Within +that is one subdirectory for each board. Within that is the build output for +that commit/board combination. + +Buildman also create working directories for each thread, in a .bm-work/ +subdirectory in the base dir. + +As an example, say we are building branch 'us-net' for boards 'sandbox' and +'seaboard', and say that us-net has two commits. We will have directories +like this: + +us-net/ base directory + 01_of_02_g4ed4ebc_net--Add-tftp-speed-/ + sandbox/ + u-boot.bin + seaboard/ + u-boot.bin + 02_of_02_g4ed4ebc_net--Check-tftp-comp/ + sandbox/ + u-boot.bin + seaboard/ + u-boot.bin + .bm-work/ + 00/ working directory for thread 0 (contains source checkout) + build/ build output + 01/ working directory for thread 1 + build/ build output + ... +u-boot/ source directory + .git/ repository +""" + +# Possible build outcomes +OUTCOME_OK, OUTCOME_WARNING, OUTCOME_ERROR, OUTCOME_UNKNOWN = range(4) + +# Translate a commit subject into a valid filename +trans_valid_chars = string.maketrans("/: ", "---") + + +def Mkdir(dirname): + """Make a directory if it doesn't already exist. + + Args: + dirname: Directory to create + """ + try: + os.mkdir(dirname) + except OSError as err: + if err.errno == errno.EEXIST: + pass + else: + raise + +class BuilderJob: + """Holds information about a job to be performed by a thread + + Members: + board: Board object to build + commits: List of commit options to build. + """ + def __init__(self): + self.board = None + self.commits = [] + + +class ResultThread(threading.Thread): + """This thread processes results from builder threads. + + It simply passes the results on to the builder. There is only one + result thread, and this helps to serialise the build output. + """ + def __init__(self, builder): + """Set up a new result thread + + Args: + builder: Builder which will be sent each result + """ + threading.Thread.__init__(self) + self.builder = builder + + def run(self): + """Called to start up the result thread. + + We collect the next result job and pass it on to the build. + """ + while True: + result = self.builder.out_queue.get() + self.builder.ProcessResult(result) + self.builder.out_queue.task_done() + + +class BuilderThread(threading.Thread): + """This thread builds U-Boot for a particular board. + + An input queue provides each new job. We run 'make' to build U-Boot + and then pass the results on to the output queue. + + Members: + builder: The builder which contains information we might need + thread_num: Our thread number (0-n-1), used to decide on a + temporary directory + """ + def __init__(self, builder, thread_num): + """Set up a new builder thread""" + threading.Thread.__init__(self) + self.builder = builder + self.thread_num = thread_num + + def Make(self, commit, brd, stage, cwd, *args, **kwargs): + """Run 'make' on a particular commit and board. + + The source code will already be checked out, so the 'commit' + argument is only for information. + + Args: + commit: Commit object that is being built + brd: Board object that is being built + stage: Stage of the build. Valid stages are: + distclean - can be called to clean source + config - called to configure for a board + build - the main make invocation - it does the build + args: A list of arguments to pass to 'make' + kwargs: A list of keyword arguments to pass to command.RunPipe() + + Returns: + CommandResult object + """ + return self.builder.do_make(commit, brd, stage, cwd, *args, + **kwargs) + + def RunCommit(self, commit_upto, brd, work_dir, do_config, force_build): + """Build a particular commit. + + If the build is already done, and we are not forcing a build, we skip + the build and just return the previously-saved results. + + Args: + commit_upto: Commit number to build (0...n-1) + brd: Board object to build + work_dir: Directory to which the source will be checked out + do_config: True to run a make <board>_config on the source + force_build: Force a build even if one was previously done + + Returns: + tuple containing: + - CommandResult object containing the results of the build + - boolean indicating whether 'make config' is still needed + """ + # Create a default result - it will be overwritte by the call to + # self.Make() below, in the event that we do a build. + result = command.CommandResult() + result.return_code = 0 + out_dir = os.path.join(work_dir, 'build') + + # Check if the job was already completed last time + done_file = self.builder.GetDoneFile(commit_upto, brd.target) + result.already_done = os.path.exists(done_file) + if result.already_done and not force_build: + # Get the return code from that build and use it + with open(done_file, 'r') as fd: + result.return_code = int(fd.readline()) + err_file = self.builder.GetErrFile(commit_upto, brd.target) + if os.path.exists(err_file) and os.stat(err_file).st_size: + result.stderr = 'bad' + else: + # We are going to have to build it. First, get a toolchain + if not self.toolchain: + try: + self.toolchain = self.builder.toolchains.Select(brd.arch) + except ValueError as err: + result.return_code = 10 + result.stdout = '' + result.stderr = str(err) + # TODO(sjg@chromium.org): This gets swallowed, but needs + # to be reported. + + if self.toolchain: + # Checkout the right commit + if commit_upto is not None: + commit = self.builder.commits[commit_upto] + if self.builder.checkout: + git_dir = os.path.join(work_dir, '.git') + gitutil.Checkout(commit.hash, git_dir, work_dir, + force=True) + else: + commit = self.builder.commit # Ick, fix this for BuildCommits() + + # Set up the environment and command line + env = self.toolchain.MakeEnvironment() + Mkdir(out_dir) + args = ['O=build', '-s'] + if self.builder.num_jobs is not None: + args.extend(['-j', str(self.builder.num_jobs)]) + config_args = ['%s_config' % brd.target] + config_out = '' + args.extend(self.builder.toolchains.GetMakeArguments(brd)) + + # If we need to reconfigure, do that now + if do_config: + result = self.Make(commit, brd, 'distclean', work_dir, + 'distclean', *args, env=env) + result = self.Make(commit, brd, 'config', work_dir, + *(args + config_args), env=env) + config_out = result.combined + do_config = False # No need to configure next time + if result.return_code == 0: + result = self.Make(commit, brd, 'build', work_dir, *args, + env=env) + result.stdout = config_out + result.stdout + else: + result.return_code = 1 + result.stderr = 'No tool chain for %s\n' % brd.arch + result.already_done = False + + result.toolchain = self.toolchain + result.brd = brd + result.commit_upto = commit_upto + result.out_dir = out_dir + return result, do_config + + def _WriteResult(self, result, keep_outputs): + """Write a built result to the output directory. + + Args: + result: CommandResult object containing result to write + keep_outputs: True to store the output binaries, False + to delete them + """ + # Fatal error + if result.return_code < 0: + return + + # Aborted? + if result.stderr and 'No child processes' in result.stderr: + return + + if result.already_done: + return + + # Write the output and stderr + output_dir = self.builder._GetOutputDir(result.commit_upto) + Mkdir(output_dir) + build_dir = self.builder.GetBuildDir(result.commit_upto, + result.brd.target) + Mkdir(build_dir) + + outfile = os.path.join(build_dir, 'log') + with open(outfile, 'w') as fd: + if result.stdout: + fd.write(result.stdout) + + errfile = self.builder.GetErrFile(result.commit_upto, + result.brd.target) + if result.stderr: + with open(errfile, 'w') as fd: + fd.write(result.stderr) + elif os.path.exists(errfile): + os.remove(errfile) + + if result.toolchain: + # Write the build result and toolchain information. + done_file = self.builder.GetDoneFile(result.commit_upto, + result.brd.target) + with open(done_file, 'w') as fd: + fd.write('%s' % result.return_code) + with open(os.path.join(build_dir, 'toolchain'), 'w') as fd: + print >>fd, 'gcc', result.toolchain.gcc + print >>fd, 'path', result.toolchain.path + print >>fd, 'cross', result.toolchain.cross + print >>fd, 'arch', result.toolchain.arch + fd.write('%s' % result.return_code) + + with open(os.path.join(build_dir, 'toolchain'), 'w') as fd: + print >>fd, 'gcc', result.toolchain.gcc + print >>fd, 'path', result.toolchain.path + + # Write out the image and function size information and an objdump + env = result.toolchain.MakeEnvironment() + lines = [] + for fname in ['u-boot', 'spl/u-boot-spl']: + cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname] + nm_result = command.RunPipe([cmd], capture=True, + capture_stderr=True, cwd=result.out_dir, + raise_on_error=False, env=env) + if nm_result.stdout: + nm = self.builder.GetFuncSizesFile(result.commit_upto, + result.brd.target, fname) + with open(nm, 'w') as fd: + print >>fd, nm_result.stdout, + + cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname] + dump_result = command.RunPipe([cmd], capture=True, + capture_stderr=True, cwd=result.out_dir, + raise_on_error=False, env=env) + rodata_size = '' + if dump_result.stdout: + objdump = self.builder.GetObjdumpFile(result.commit_upto, + result.brd.target, fname) + with open(objdump, 'w') as fd: + print >>fd, dump_result.stdout, + for line in dump_result.stdout.splitlines(): + fields = line.split() + if len(fields) > 5 and fields[1] == '.rodata': + rodata_size = fields[2] + + cmd = ['%ssize' % self.toolchain.cross, fname] + size_result = command.RunPipe([cmd], capture=True, + capture_stderr=True, cwd=result.out_dir, + raise_on_error=False, env=env) + if size_result.stdout: + lines.append(size_result.stdout.splitlines()[1] + ' ' + + rodata_size) + + # Write out the image sizes file. This is similar to the output + # of binutil's 'size' utility, but it omits the header line and + # adds an additional hex value at the end of each line for the + # rodata size + if len(lines): + sizes = self.builder.GetSizesFile(result.commit_upto, + result.brd.target) + with open(sizes, 'w') as fd: + print >>fd, '\n'.join(lines) + + # Now write the actual build output + if keep_outputs: + patterns = ['u-boot', '*.bin', 'u-boot.dtb', '*.map', + 'include/autoconf.mk', 'spl/u-boot-spl', + 'spl/u-boot-spl.bin'] + for pattern in patterns: + file_list = glob.glob(os.path.join(result.out_dir, pattern)) + for fname in file_list: + shutil.copy(fname, build_dir) + + + def RunJob(self, job): + """Run a single job + + A job consists of a building a list of commits for a particular board. + + Args: + job: Job to build + """ + brd = job.board + work_dir = self.builder.GetThreadDir(self.thread_num) + self.toolchain = None + if job.commits: + # Run 'make board_config' on the first commit + do_config = True + commit_upto = 0 + force_build = False + for commit_upto in range(0, len(job.commits), job.step): + result, request_config = self.RunCommit(commit_upto, brd, + work_dir, do_config, + force_build or self.builder.force_build) + failed = result.return_code or result.stderr + if failed and not do_config: + # If our incremental build failed, try building again + # with a reconfig. + if self.builder.force_config_on_failure: + result, request_config = self.RunCommit(commit_upto, + brd, work_dir, True, True) + do_config = request_config + + # If we built that commit, then config is done. But if we got + # an warning, reconfig next time to force it to build the same + # files that created warnings this time. Otherwise an + # incremental build may not build the same file, and we will + # think that the warning has gone away. + # We could avoid this by using -Werror everywhere... + # For errors, the problem doesn't happen, since presumably + # the build stopped and didn't generate output, so will retry + # that file next time. So we could detect warnings and deal + # with them specially here. For now, we just reconfigure if + # anything goes work. + # Of course this is substantially slower if there are build + # errors/warnings (e.g. 2-3x slower even if only 10% of builds + # have problems). + if (failed and not result.already_done and not do_config and + self.builder.force_config_on_failure): + # If this build failed, try the next one with a + # reconfigure. + # Sometimes if the board_config.h file changes it can mess + # with dependencies, and we get: + # make: *** No rule to make target `include/autoconf.mk', + # needed by `depend'. + do_config = True + force_build = True + else: + force_build = False + if self.builder.force_config_on_failure: + if failed: + do_config = True + result.commit_upto = commit_upto + if result.return_code < 0: + raise ValueError('Interrupt') + + # We have the build results, so output the result + self._WriteResult(result, job.keep_outputs) + self.builder.out_queue.put(result) + else: + # Just build the currently checked-out build + result = self.RunCommit(None, True) + result.commit_upto = self.builder.upto + self.builder.out_queue.put(result) + + def run(self): + """Our thread's run function + + This thread picks a job from the queue, runs it, and then goes to the + next job. + """ + alive = True + while True: + job = self.builder.queue.get() + try: + if self.builder.active and alive: + self.RunJob(job) + except Exception as err: + alive = False + print err + self.builder.queue.task_done() + + +class Builder: + """Class for building U-Boot for a particular commit. + + Public members: (many should ->private) + active: True if the builder is active and has not been stopped + already_done: Number of builds already completed + base_dir: Base directory to use for builder + checkout: True to check out source, False to skip that step. + This is used for testing. + col: terminal.Color() object + count: Number of commits to build + do_make: Method to call to invoke Make + fail: Number of builds that failed due to error + force_build: Force building even if a build already exists + force_config_on_failure: If a commit fails for a board, disable + incremental building for the next commit we build for that + board, so that we will see all warnings/errors again. + git_dir: Git directory containing source repository + last_line_len: Length of the last line we printed (used for erasing + it with new progress information) + num_jobs: Number of jobs to run at once (passed to make as -j) + num_threads: Number of builder threads to run + out_queue: Queue of results to process + re_make_err: Compiled regular expression for ignore_lines + queue: Queue of jobs to run + threads: List of active threads + toolchains: Toolchains object to use for building + upto: Current commit number we are building (0.count-1) + warned: Number of builds that produced at least one warning + + Private members: + _base_board_dict: Last-summarised Dict of boards + _base_err_lines: Last-summarised list of errors + _build_period_us: Time taken for a single build (float object). + _complete_delay: Expected delay until completion (timedelta) + _next_delay_update: Next time we plan to display a progress update + (datatime) + _show_unknown: Show unknown boards (those not built) in summary + _timestamps: List of timestamps for the completion of the last + last _timestamp_count builds. Each is a datetime object. + _timestamp_count: Number of timestamps to keep in our list. + _working_dir: Base working directory containing all threads + """ + class Outcome: + """Records a build outcome for a single make invocation + + Public Members: + rc: Outcome value (OUTCOME_...) + err_lines: List of error lines or [] if none + sizes: Dictionary of image size information, keyed by filename + - Each value is itself a dictionary containing + values for 'text', 'data' and 'bss', being the integer + size in bytes of each section. + func_sizes: Dictionary keyed by filename - e.g. 'u-boot'. Each + value is itself a dictionary: + key: function name + value: Size of function in bytes + """ + def __init__(self, rc, err_lines, sizes, func_sizes): + self.rc = rc + self.err_lines = err_lines + self.sizes = sizes + self.func_sizes = func_sizes + + def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs, + checkout=True, show_unknown=True, step=1): + """Create a new Builder object + + Args: + toolchains: Toolchains object to use for building + base_dir: Base directory to use for builder + git_dir: Git directory containing source repository + num_threads: Number of builder threads to run + num_jobs: Number of jobs to run at once (passed to make as -j) + checkout: True to check out source, False to skip that step. + This is used for testing. + show_unknown: Show unknown boards (those not built) in summary + step: 1 to process every commit, n to process every nth commit + """ + self.toolchains = toolchains + self.base_dir = base_dir + self._working_dir = os.path.join(base_dir, '.bm-work') + self.threads = [] + self.active = True + self.do_make = self.Make + self.checkout = checkout + self.num_threads = num_threads + self.num_jobs = num_jobs + self.already_done = 0 + self.force_build = False + self.git_dir = git_dir + self._show_unknown = show_unknown + self._timestamp_count = 10 + self._build_period_us = None + self._complete_delay = None + self._next_delay_update = datetime.now() + self.force_config_on_failure = True + self._step = step + + self.col = terminal.Color() + + self.queue = Queue.Queue() + self.out_queue = Queue.Queue() + for i in range(self.num_threads): + t = BuilderThread(self, i) + t.setDaemon(True) + t.start() + self.threads.append(t) + + self.last_line_len = 0 + t = ResultThread(self) + t.setDaemon(True) + t.start() + self.threads.append(t) + + ignore_lines = ['(make.*Waiting for unfinished)', '(Segmentation fault)'] + self.re_make_err = re.compile('|'.join(ignore_lines)) + + def __del__(self): + """Get rid of all threads created by the builder""" + for t in self.threads: + del t + + def _AddTimestamp(self): + """Add a new timestamp to the list and record the build period. + + The build period is the length of time taken to perform a single + build (one board, one commit). + """ + now = datetime.now() + self._timestamps.append(now) + count = len(self._timestamps) + delta = self._timestamps[-1] - self._timestamps[0] + seconds = delta.total_seconds() + + # If we have enough data, estimate build period (time taken for a + # single build) and therefore completion time. + if count > 1 and self._next_delay_update < now: + self._next_delay_update = now + timedelta(seconds=2) + if seconds > 0: + self._build_period = float(seconds) / count + todo = self.count - self.upto + self._complete_delay = timedelta(microseconds= + self._build_period * todo * 1000000) + # Round it + self._complete_delay -= timedelta( + microseconds=self._complete_delay.microseconds) + + if seconds > 60: + self._timestamps.popleft() + count -= 1 + + def ClearLine(self, length): + """Clear any characters on the current line + + Make way for a new line of length 'length', by outputting enough + spaces to clear out the old line. Then remember the new length for + next time. + + Args: + length: Length of new line, in characters + """ + if length < self.last_line_len: + print ' ' * (self.last_line_len - length), + print '\r', + self.last_line_len = length + sys.stdout.flush() + + def SelectCommit(self, commit, checkout=True): + """Checkout the selected commit for this build + """ + self.commit = commit + if checkout and self.checkout: + gitutil.Checkout(commit.hash) + + def Make(self, commit, brd, stage, cwd, *args, **kwargs): + """Run make + + Args: + commit: Commit object that is being built + brd: Board object that is being built + stage: Stage that we are at (distclean, config, build) + cwd: Directory where make should be run + args: Arguments to pass to make + kwargs: Arguments to pass to command.RunPipe() + """ + cmd = ['make'] + list(args) + result = command.RunPipe([cmd], capture=True, capture_stderr=True, + cwd=cwd, raise_on_error=False, **kwargs) + return result + + def ProcessResult(self, result): + """Process the result of a build, showing progress information + + Args: + result: A CommandResult object + """ + col = terminal.Color() + if result: + target = result.brd.target + + if result.return_code < 0: + self.active = False + command.StopAll() + return + + self.upto += 1 + if result.return_code != 0: + self.fail += 1 + elif result.stderr: + self.warned += 1 + if result.already_done: + self.already_done += 1 + else: + target = '(starting)' + + # Display separate counts for ok, warned and fail + ok = self.upto - self.warned - self.fail + line = '\r' + self.col.Color(self.col.GREEN, '%5d' % ok) + line += self.col.Color(self.col.YELLOW, '%5d' % self.warned) + line += self.col.Color(self.col.RED, '%5d' % self.fail) + + name = ' /%-5d ' % self.count + + # Add our current completion time estimate + self._AddTimestamp() + if self._complete_delay: + name += '%s : ' % self._complete_delay + # When building all boards for a commit, we can print a commit + # progress message. + if result and result.commit_upto is None: + name += 'commit %2d/%-3d' % (self.commit_upto + 1, + self.commit_count) + + name += target + print line + name, + length = 13 + len(name) + self.ClearLine(length) + + def _GetOutputDir(self, commit_upto): + """Get the name of the output directory for a commit number + + The output directory is typically .../<branch>/<commit>. + + Args: + commit_upto: Commit number to use (0..self.count-1) + """ + commit = self.commits[commit_upto] + subject = commit.subject.translate(trans_valid_chars) + commit_dir = ('%02d_of_%02d_g%s_%s' % (commit_upto + 1, + self.commit_count, commit.hash, subject[:20])) + output_dir = os.path.join(self.base_dir, commit_dir) + return output_dir + + def GetBuildDir(self, commit_upto, target): + """Get the name of the build directory for a commit number + + The build directory is typically .../<branch>/<commit>/<target>. + + Args: + commit_upto: Commit number to use (0..self.count-1) + target: Target name + """ + output_dir = self._GetOutputDir(commit_upto) + return os.path.join(output_dir, target) + + def GetDoneFile(self, commit_upto, target): + """Get the name of the done file for a commit number + + Args: + commit_upto: Commit number to use (0..self.count-1) + target: Target name + """ + return os.path.join(self.GetBuildDir(commit_upto, target), 'done') + + def GetSizesFile(self, commit_upto, target): + """Get the name of the sizes file for a commit number + + Args: + commit_upto: Commit number to use (0..self.count-1) + target: Target name + """ + return os.path.join(self.GetBuildDir(commit_upto, target), 'sizes') + + def GetFuncSizesFile(self, commit_upto, target, elf_fname): + """Get the name of the funcsizes file for a commit number and ELF file + + Args: + commit_upto: Commit number to use (0..self.count-1) + target: Target name + elf_fname: Filename of elf image + """ + return os.path.join(self.GetBuildDir(commit_upto, target), + '%s.sizes' % elf_fname.replace('/', '-')) + + def GetObjdumpFile(self, commit_upto, target, elf_fname): + """Get the name of the objdump file for a commit number and ELF file + + Args: + commit_upto: Commit number to use (0..self.count-1) + target: Target name + elf_fname: Filename of elf image + """ + return os.path.join(self.GetBuildDir(commit_upto, target), + '%s.objdump' % elf_fname.replace('/', '-')) + + def GetErrFile(self, commit_upto, target): + """Get the name of the err file for a commit number + + Args: + commit_upto: Commit number to use (0..self.count-1) + target: Target name + """ + output_dir = self.GetBuildDir(commit_upto, target) + return os.path.join(output_dir, 'err') + + def FilterErrors(self, lines): + """Filter out errors in which we have no interest + + We should probably use map(). + + Args: + lines: List of error lines, each a string + Returns: + New list with only interesting lines included + """ + out_lines = [] + for line in lines: + if not self.re_make_err.search(line): + out_lines.append(line) + return out_lines + + def ReadFuncSizes(self, fname, fd): + """Read function sizes from the output of 'nm' + + Args: + fd: File containing data to read + fname: Filename we are reading from (just for errors) + + Returns: + Dictionary containing size of each function in bytes, indexed by + function name. + """ + sym = {} + for line in fd.readlines(): + try: + size, type, name = line[:-1].split() + except: + print "Invalid line in file '%s': '%s'" % (fname, line[:-1]) + continue + if type in 'tTdDbB': + # function names begin with '.' on 64-bit powerpc + if '.' in name[1:]: + name = 'static.' + name.split('.')[0] + sym[name] = sym.get(name, 0) + int(size, 16) + return sym + + def GetBuildOutcome(self, commit_upto, target, read_func_sizes): + """Work out the outcome of a build. + + Args: + commit_upto: Commit number to check (0..n-1) + target: Target board to check + read_func_sizes: True to read function size information + + Returns: + Outcome object + """ + done_file = self.GetDoneFile(commit_upto, target) + sizes_file = self.GetSizesFile(commit_upto, target) + sizes = {} + func_sizes = {} + if os.path.exists(done_file): + with open(done_file, 'r') as fd: + return_code = int(fd.readline()) + err_lines = [] + err_file = self.GetErrFile(commit_upto, target) + if os.path.exists(err_file): + with open(err_file, 'r') as fd: + err_lines = self.FilterErrors(fd.readlines()) + + # Decide whether the build was ok, failed or created warnings + if return_code: + rc = OUTCOME_ERROR + elif len(err_lines): + rc = OUTCOME_WARNING + else: + rc = OUTCOME_OK + + # Convert size information to our simple format + if os.path.exists(sizes_file): + with open(sizes_file, 'r') as fd: + for line in fd.readlines(): + values = line.split() + rodata = 0 + if len(values) > 6: + rodata = int(values[6], 16) + size_dict = { + 'all' : int(values[0]) + int(values[1]) + + int(values[2]), + 'text' : int(values[0]) - rodata, + 'data' : int(values[1]), + 'bss' : int(values[2]), + 'rodata' : rodata, + } + sizes[values[5]] = size_dict + + if read_func_sizes: + pattern = self.GetFuncSizesFile(commit_upto, target, '*') + for fname in glob.glob(pattern): + with open(fname, 'r') as fd: + dict_name = os.path.basename(fname).replace('.sizes', + '') + func_sizes[dict_name] = self.ReadFuncSizes(fname, fd) + + return Builder.Outcome(rc, err_lines, sizes, func_sizes) + + return Builder.Outcome(OUTCOME_UNKNOWN, [], {}, {}) + + def GetResultSummary(self, boards_selected, commit_upto, read_func_sizes): + """Calculate a summary of the results of building a commit. + + Args: + board_selected: Dict containing boards to summarise + commit_upto: Commit number to summarize (0..self.count-1) + read_func_sizes: True to read function size information + + Returns: + Tuple: + Dict containing boards which passed building this commit. + keyed by board.target + List containing a summary of error/warning lines + """ + board_dict = {} + err_lines_summary = [] + + for board in boards_selected.itervalues(): + outcome = self.GetBuildOutcome(commit_upto, board.target, + read_func_sizes) + board_dict[board.target] = outcome + for err in outcome.err_lines: + if err and not err.rstrip() in err_lines_summary: + err_lines_summary.append(err.rstrip()) + return board_dict, err_lines_summary + + def AddOutcome(self, board_dict, arch_list, changes, char, color): + """Add an output to our list of outcomes for each architecture + + This simple function adds failing boards (changes) to the + relevant architecture string, so we can print the results out + sorted by architecture. + + Args: + board_dict: Dict containing all boards + arch_list: Dict keyed by arch name. Value is a string containing + a list of board names which failed for that arch. + changes: List of boards to add to arch_list + color: terminal.Colour object + """ + done_arch = {} + for target in changes: + if target in board_dict: + arch = board_dict[target].arch + else: + arch = 'unknown' + str = self.col.Color(color, ' ' + target) + if not arch in done_arch: + str = self.col.Color(color, char) + ' ' + str + done_arch[arch] = True + if not arch in arch_list: + arch_list[arch] = str + else: + arch_list[arch] += str + + + def ColourNum(self, num): + color = self.col.RED if num > 0 else self.col.GREEN + if num == 0: + return '0' + return self.col.Color(color, str(num)) + + def ResetResultSummary(self, board_selected): + """Reset the results summary ready for use. + + Set up the base board list to be all those selected, and set the + error lines to empty. + + Following this, calls to PrintResultSummary() will use this + information to work out what has changed. + + Args: + board_selected: Dict containing boards to summarise, keyed by + board.target + """ + self._base_board_dict = {} + for board in board_selected: + self._base_board_dict[board] = Builder.Outcome(0, [], [], {}) + self._base_err_lines = [] + + def PrintFuncSizeDetail(self, fname, old, new): + grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0 + delta, common = [], {} + + for a in old: + if a in new: + common[a] = 1 + + for name in old: + if name not in common: + remove += 1 + down += old[name] + delta.append([-old[name], name]) + + for name in new: + if name not in common: + add += 1 + up += new[name] + delta.append([new[name], name]) + + for name in common: + diff = new.get(name, 0) - old.get(name, 0) + if diff > 0: + grow, up = grow + 1, up + diff + elif diff < 0: + shrink, down = shrink + 1, down - diff + delta.append([diff, name]) + + delta.sort() + delta.reverse() + + args = [add, -remove, grow, -shrink, up, -down, up - down] + if max(args) == 0: + return + args = [self.ColourNum(x) for x in args] + indent = ' ' * 15 + print ('%s%s: add: %s/%s, grow: %s/%s bytes: %s/%s (%s)' % + tuple([indent, self.col.Color(self.col.YELLOW, fname)] + args)) + print '%s %-38s %7s %7s %+7s' % (indent, 'function', 'old', 'new', + 'delta') + for diff, name in delta: + if diff: + color = self.col.RED if diff > 0 else self.col.GREEN + msg = '%s %-38s %7s %7s %+7d' % (indent, name, + old.get(name, '-'), new.get(name,'-'), diff) + print self.col.Color(color, msg) + + + def PrintSizeDetail(self, target_list, show_bloat): + """Show details size information for each board + + Args: + target_list: List of targets, each a dict containing: + 'target': Target name + 'total_diff': Total difference in bytes across all areas + <part_name>: Difference for that part + show_bloat: Show detail for each function + """ + targets_by_diff = sorted(target_list, reverse=True, + key=lambda x: x['_total_diff']) + for result in targets_by_diff: + printed_target = False + for name in sorted(result): + diff = result[name] + if name.startswith('_'): + continue + if diff != 0: + color = self.col.RED if diff > 0 else self.col.GREEN + msg = ' %s %+d' % (name, diff) + if not printed_target: + print '%10s %-15s:' % ('', result['_target']), + printed_target = True + print self.col.Color(color, msg), + if printed_target: + print + if show_bloat: + target = result['_target'] + outcome = result['_outcome'] + base_outcome = self._base_board_dict[target] + for fname in outcome.func_sizes: + self.PrintFuncSizeDetail(fname, + base_outcome.func_sizes[fname], + outcome.func_sizes[fname]) + + + def PrintSizeSummary(self, board_selected, board_dict, show_detail, + show_bloat): + """Print a summary of image sizes broken down by section. + + The summary takes the form of one line per architecture. The + line contains deltas for each of the sections (+ means the section + got bigger, - means smaller). The nunmbers are the average number + of bytes that a board in this section increased by. + + For example: + powerpc: (622 boards) text -0.0 + arm: (285 boards) text -0.0 + nds32: (3 boards) text -8.0 + + Args: + board_selected: Dict containing boards to summarise, keyed by + board.target + board_dict: Dict containing boards for which we built this + commit, keyed by board.target. The value is an Outcome object. + show_detail: Show detail for each board + show_bloat: Show detail for each function + """ + arch_list = {} + arch_count = {} + + # Calculate changes in size for different image parts + # The previous sizes are in Board.sizes, for each board + for target in board_dict: + if target not in board_selected: + continue + base_sizes = self._base_board_dict[target].sizes + outcome = board_dict[target] + sizes = outcome.sizes + + # Loop through the list of images, creating a dict of size + # changes for each image/part. We end up with something like + # {'target' : 'snapper9g45, 'data' : 5, 'u-boot-spl:text' : -4} + # which means that U-Boot data increased by 5 bytes and SPL + # text decreased by 4. + err = {'_target' : target} + for image in sizes: + if image in base_sizes: + base_image = base_sizes[image] + # Loop through the text, data, bss parts + for part in sorted(sizes[image]): + diff = sizes[image][part] - base_image[part] + col = None + if diff: + if image == 'u-boot': + name = part + else: + name = image + ':' + part + err[name] = diff + arch = board_selected[target].arch + if not arch in arch_count: + arch_count[arch] = 1 + else: + arch_count[arch] += 1 + if not sizes: + pass # Only add to our list when we have some stats + elif not arch in arch_list: + arch_list[arch] = [err] + else: + arch_list[arch].append(err) + + # We now have a list of image size changes sorted by arch + # Print out a summary of these + for arch, target_list in arch_list.iteritems(): + # Get total difference for each type + totals = {} + for result in target_list: + total = 0 + for name, diff in result.iteritems(): + if name.startswith('_'): + continue + total += diff + if name in totals: + totals[name] += diff + else: + totals[name] = diff + result['_total_diff'] = total + result['_outcome'] = board_dict[result['_target']] + + count = len(target_list) + printed_arch = False + for name in sorted(totals): + diff = totals[name] + if diff: + # Display the average difference in this name for this + # architecture + avg_diff = float(diff) / count + color = self.col.RED if avg_diff > 0 else self.col.GREEN + msg = ' %s %+1.1f' % (name, avg_diff) + if not printed_arch: + print '%10s: (for %d/%d boards)' % (arch, count, + arch_count[arch]), + printed_arch = True + print self.col.Color(color, msg), + + if printed_arch: + print + if show_detail: + self.PrintSizeDetail(target_list, show_bloat) + + + def PrintResultSummary(self, board_selected, board_dict, err_lines, + show_sizes, show_detail, show_bloat): + """Compare results with the base results and display delta. + + Only boards mentioned in board_selected will be considered. This + function is intended to be called repeatedly with the results of + each commit. It therefore shows a 'diff' between what it saw in + the last call and what it sees now. + + Args: + board_selected: Dict containing boards to summarise, keyed by + board.target + board_dict: Dict containing boards for which we built this + commit, keyed by board.target. The value is an Outcome object. + err_lines: A list of errors for this commit, or [] if there is + none, or we don't want to print errors + show_sizes: Show image size deltas + show_detail: Show detail for each board + show_bloat: Show detail for each function + """ + better = [] # List of boards fixed since last commit + worse = [] # List of new broken boards since last commit + new = [] # List of boards that didn't exist last time + unknown = [] # List of boards that were not built + + for target in board_dict: + if target not in board_selected: + continue + + # If the board was built last time, add its outcome to a list + if target in self._base_board_dict: + base_outcome = self._base_board_dict[target].rc + outcome = board_dict[target] + if outcome.rc == OUTCOME_UNKNOWN: + unknown.append(target) + elif outcome.rc < base_outcome: + better.append(target) + elif outcome.rc > base_outcome: + worse.append(target) + else: + new.append(target) + + # Get a list of errors that have appeared, and disappeared + better_err = [] + worse_err = [] + for line in err_lines: + if line not in self._base_err_lines: + worse_err.append('+' + line) + for line in self._base_err_lines: + if line not in err_lines: + better_err.append('-' + line) + + # Display results by arch + if better or worse or unknown or new or worse_err or better_err: + arch_list = {} + self.AddOutcome(board_selected, arch_list, better, '', + self.col.GREEN) + self.AddOutcome(board_selected, arch_list, worse, '+', + self.col.RED) + self.AddOutcome(board_selected, arch_list, new, '*', self.col.BLUE) + if self._show_unknown: + self.AddOutcome(board_selected, arch_list, unknown, '?', + self.col.MAGENTA) + for arch, target_list in arch_list.iteritems(): + print '%10s: %s' % (arch, target_list) + if better_err: + print self.col.Color(self.col.GREEN, '\n'.join(better_err)) + if worse_err: + print self.col.Color(self.col.RED, '\n'.join(worse_err)) + + if show_sizes: + self.PrintSizeSummary(board_selected, board_dict, show_detail, + show_bloat) + + # Save our updated information for the next call to this function + self._base_board_dict = board_dict + self._base_err_lines = err_lines + + # Get a list of boards that did not get built, if needed + not_built = [] + for board in board_selected: + if not board in board_dict: + not_built.append(board) + if not_built: + print "Boards not built (%d): %s" % (len(not_built), + ', '.join(not_built)) + + + def ShowSummary(self, commits, board_selected, show_errors, show_sizes, + show_detail, show_bloat): + """Show a build summary for U-Boot for a given board list. + + Reset the result summary, then repeatedly call GetResultSummary on + each commit's results, then display the differences we see. + + Args: + commit: Commit objects to summarise + board_selected: Dict containing boards to summarise + show_errors: Show errors that occured + show_sizes: Show size deltas + show_detail: Show detail for each board + show_bloat: Show detail for each function + """ + self.commit_count = len(commits) + self.commits = commits + self.ResetResultSummary(board_selected) + + for commit_upto in range(0, self.commit_count, self._step): + board_dict, err_lines = self.GetResultSummary(board_selected, + commit_upto, read_func_sizes=show_bloat) + msg = '%02d: %s' % (commit_upto + 1, commits[commit_upto].subject) + print self.col.Color(self.col.BLUE, msg) + self.PrintResultSummary(board_selected, board_dict, + err_lines if show_errors else [], show_sizes, show_detail, + show_bloat) + + + def SetupBuild(self, board_selected, commits): + """Set up ready to start a build. + + Args: + board_selected: Selected boards to build + commits: Selected commits to build + """ + # First work out how many commits we will build + count = (len(commits) + self._step - 1) / self._step + self.count = len(board_selected) * count + self.upto = self.warned = self.fail = 0 + self._timestamps = collections.deque() + + def BuildBoardsForCommit(self, board_selected, keep_outputs): + """Build all boards for a single commit""" + self.SetupBuild(board_selected) + self.count = len(board_selected) + for brd in board_selected.itervalues(): + job = BuilderJob() + job.board = brd + job.commits = None + job.keep_outputs = keep_outputs + self.queue.put(brd) + + self.queue.join() + self.out_queue.join() + print + self.ClearLine(0) + + def BuildCommits(self, commits, board_selected, show_errors, keep_outputs): + """Build all boards for all commits (non-incremental)""" + self.commit_count = len(commits) + + self.ResetResultSummary(board_selected) + for self.commit_upto in range(self.commit_count): + self.SelectCommit(commits[self.commit_upto]) + self.SelectOutputDir() + Mkdir(self.output_dir) + + self.BuildBoardsForCommit(board_selected, keep_outputs) + board_dict, err_lines = self.GetResultSummary() + self.PrintResultSummary(board_selected, board_dict, + err_lines if show_errors else []) + + if self.already_done: + print '%d builds already done' % self.already_done + + def GetThreadDir(self, thread_num): + """Get the directory path to the working dir for a thread. + + Args: + thread_num: Number of thread to check. + """ + return os.path.join(self._working_dir, '%02d' % thread_num) + + def _PrepareThread(self, thread_num): + """Prepare the working directory for a thread. + + This clones or fetches the repo into the thread's work directory. + + Args: + thread_num: Thread number (0, 1, ...) + """ + thread_dir = self.GetThreadDir(thread_num) + Mkdir(thread_dir) + git_dir = os.path.join(thread_dir, '.git') + + # Clone the repo if it doesn't already exist + # TODO(sjg@chromium): Perhaps some git hackery to symlink instead, so + # we have a private index but uses the origin repo's contents? + if self.git_dir: + src_dir = os.path.abspath(self.git_dir) + if os.path.exists(git_dir): + gitutil.Fetch(git_dir, thread_dir) + else: + print 'Cloning repo for thread %d' % thread_num + gitutil.Clone(src_dir, thread_dir) + + def _PrepareWorkingSpace(self, max_threads): + """Prepare the working directory for use. + + Set up the git repo for each thread. + + Args: + max_threads: Maximum number of threads we expect to need. + """ + Mkdir(self._working_dir) + for thread in range(max_threads): + self._PrepareThread(thread) + + def _PrepareOutputSpace(self): + """Get the output directories ready to receive files. + + We delete any output directories which look like ones we need to + create. Having left over directories is confusing when the user wants + to check the output manually. + """ + dir_list = [] + for commit_upto in range(self.commit_count): + dir_list.append(self._GetOutputDir(commit_upto)) + + for dirname in glob.glob(os.path.join(self.base_dir, '*')): + if dirname not in dir_list: + shutil.rmtree(dirname) + + def BuildBoards(self, commits, board_selected, show_errors, keep_outputs): + """Build all commits for a list of boards + + Args: + commits: List of commits to be build, each a Commit object + boards_selected: Dict of selected boards, key is target name, + value is Board object + show_errors: True to show summarised error/warning info + keep_outputs: True to save build output files + """ + self.commit_count = len(commits) + self.commits = commits + + self.ResetResultSummary(board_selected) + Mkdir(self.base_dir) + self._PrepareWorkingSpace(min(self.num_threads, len(board_selected))) + self._PrepareOutputSpace() + self.SetupBuild(board_selected, commits) + self.ProcessResult(None) + + # Create jobs to build all commits for each board + for brd in board_selected.itervalues(): + job = BuilderJob() + job.board = brd + job.commits = commits + job.keep_outputs = keep_outputs + job.step = self._step + self.queue.put(job) + + # Wait until all jobs are started + self.queue.join() + + # Wait until we have processed all output + self.out_queue.join() + print + self.ClearLine(0) diff --git a/qemu/roms/u-boot/tools/buildman/buildman b/qemu/roms/u-boot/tools/buildman/buildman new file mode 120000 index 000000000..e4fba2d4b --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/buildman @@ -0,0 +1 @@ +buildman.py
\ No newline at end of file diff --git a/qemu/roms/u-boot/tools/buildman/buildman.py b/qemu/roms/u-boot/tools/buildman/buildman.py new file mode 100755 index 000000000..73a5483d4 --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/buildman.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# +# Copyright (c) 2012 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +"""See README for more information""" + +import multiprocessing +from optparse import OptionParser +import os +import re +import sys +import unittest + +# Bring in the patman libraries +our_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(our_path, '../patman')) + +# Our modules +import board +import builder +import checkpatch +import command +import control +import doctest +import gitutil +import patchstream +import terminal +import toolchain + +def RunTests(): + import test + import doctest + + result = unittest.TestResult() + for module in ['toolchain']: + suite = doctest.DocTestSuite(module) + suite.run(result) + + # TODO: Surely we can just 'print' result? + print result + for test, err in result.errors: + print err + for test, err in result.failures: + print err + + sys.argv = [sys.argv[0]] + suite = unittest.TestLoader().loadTestsFromTestCase(test.TestBuild) + result = unittest.TestResult() + suite.run(result) + + # TODO: Surely we can just 'print' result? + print result + for test, err in result.errors: + print err + for test, err in result.failures: + print err + + +parser = OptionParser() +parser.add_option('-b', '--branch', type='string', + help='Branch name to build') +parser.add_option('-B', '--bloat', dest='show_bloat', + action='store_true', default=False, + help='Show changes in function code size for each board') +parser.add_option('-c', '--count', dest='count', type='int', + default=-1, help='Run build on the top n commits') +parser.add_option('-e', '--show_errors', action='store_true', + default=False, help='Show errors and warnings') +parser.add_option('-f', '--force-build', dest='force_build', + action='store_true', default=False, + help='Force build of boards even if already built') +parser.add_option('-d', '--detail', dest='show_detail', + action='store_true', default=False, + help='Show detailed information for each board in summary') +parser.add_option('-g', '--git', type='string', + help='Git repo containing branch to build', default='.') +parser.add_option('-H', '--full-help', action='store_true', dest='full_help', + default=False, help='Display the README file') +parser.add_option('-j', '--jobs', dest='jobs', type='int', + default=None, help='Number of jobs to run at once (passed to make)') +parser.add_option('-k', '--keep-outputs', action='store_true', + default=False, help='Keep all build output files (e.g. binaries)') +parser.add_option('--list-tool-chains', action='store_true', default=False, + help='List available tool chains') +parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run', + default=False, help="Do a try run (describe actions, but no nothing)") +parser.add_option('-Q', '--quick', action='store_true', + default=False, help='Do a rough build, with limited warning resolution') +parser.add_option('-s', '--summary', action='store_true', + default=False, help='Show a build summary') +parser.add_option('-S', '--show-sizes', action='store_true', + default=False, help='Show image size variation in summary') +parser.add_option('--step', type='int', + default=1, help='Only build every n commits (0=just first and last)') +parser.add_option('-t', '--test', action='store_true', dest='test', + default=False, help='run tests') +parser.add_option('-T', '--threads', type='int', + default=None, help='Number of builder threads to use') +parser.add_option('-u', '--show_unknown', action='store_true', + default=False, help='Show boards with unknown build result') +parser.add_option('-o', '--output-dir', type='string', + dest='output_dir', default='..', + help='Directory where all builds happen and buildman has its workspace (default is ../)') + +parser.usage = """buildman -b <branch> [options] + +Build U-Boot for all commits in a branch. Use -n to do a dry run""" + +(options, args) = parser.parse_args() + +# Run our meagre tests +if options.test: + RunTests() +elif options.full_help: + pager = os.getenv('PAGER') + if not pager: + pager = 'more' + fname = os.path.join(os.path.dirname(sys.argv[0]), 'README') + command.Run(pager, fname) + +# Build selected commits for selected boards +else: + control.DoBuildman(options, args) diff --git a/qemu/roms/u-boot/tools/buildman/control.py b/qemu/roms/u-boot/tools/buildman/control.py new file mode 100644 index 000000000..d2f4102ba --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/control.py @@ -0,0 +1,174 @@ +# Copyright (c) 2013 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import multiprocessing +import os +import sys + +import board +import bsettings +from builder import Builder +import gitutil +import patchstream +import terminal +import toolchain + +def GetPlural(count): + """Returns a plural 's' if count is not 1""" + return 's' if count != 1 else '' + +def GetActionSummary(is_summary, count, selected, options): + """Return a string summarising the intended action. + + Returns: + Summary string. + """ + count = (count + options.step - 1) / options.step + str = '%s %d commit%s for %d boards' % ( + 'Summary of' if is_summary else 'Building', count, GetPlural(count), + len(selected)) + str += ' (%d thread%s, %d job%s per thread)' % (options.threads, + GetPlural(options.threads), options.jobs, GetPlural(options.jobs)) + return str + +def ShowActions(series, why_selected, boards_selected, builder, options): + """Display a list of actions that we would take, if not a dry run. + + Args: + series: Series object + why_selected: Dictionary where each key is a buildman argument + provided by the user, and the value is the boards brought + in by that argument. For example, 'arm' might bring in + 400 boards, so in this case the key would be 'arm' and + the value would be a list of board names. + boards_selected: Dict of selected boards, key is target name, + value is Board object + builder: The builder that will be used to build the commits + options: Command line options object + """ + col = terminal.Color() + print 'Dry run, so not doing much. But I would do this:' + print + print GetActionSummary(False, len(series.commits), boards_selected, + options) + print 'Build directory: %s' % builder.base_dir + for upto in range(0, len(series.commits), options.step): + commit = series.commits[upto] + print ' ', col.Color(col.YELLOW, commit.hash, bright=False), + print commit.subject + print + for arg in why_selected: + if arg != 'all': + print arg, ': %d boards' % why_selected[arg] + print ('Total boards to build for each commit: %d\n' % + why_selected['all']) + +def DoBuildman(options, args): + """The main control code for buildman + + Args: + options: Command line options object + args: Command line arguments (list of strings) + """ + gitutil.Setup() + + bsettings.Setup() + options.git_dir = os.path.join(options.git, '.git') + + toolchains = toolchain.Toolchains() + toolchains.Scan(options.list_tool_chains) + if options.list_tool_chains: + toolchains.List() + print + return + + # Work out how many commits to build. We want to build everything on the + # branch. We also build the upstream commit as a control so we can see + # problems introduced by the first commit on the branch. + col = terminal.Color() + count = options.count + if count == -1: + if not options.branch: + str = 'Please use -b to specify a branch to build' + print col.Color(col.RED, str) + sys.exit(1) + count = gitutil.CountCommitsInBranch(options.git_dir, options.branch) + if count is None: + str = "Branch '%s' not found or has no upstream" % options.branch + print col.Color(col.RED, str) + sys.exit(1) + count += 1 # Build upstream commit also + + if not count: + str = ("No commits found to process in branch '%s': " + "set branch's upstream or use -c flag" % options.branch) + print col.Color(col.RED, str) + sys.exit(1) + + # Work out what subset of the boards we are building + boards = board.Boards() + boards.ReadBoards(os.path.join(options.git, 'boards.cfg')) + why_selected = boards.SelectBoards(args) + selected = boards.GetSelected() + if not len(selected): + print col.Color(col.RED, 'No matching boards found') + sys.exit(1) + + # Read the metadata from the commits. First look at the upstream commit, + # then the ones in the branch. We would like to do something like + # upstream/master~..branch but that isn't possible if upstream/master is + # a merge commit (it will list all the commits that form part of the + # merge) + range_expr = gitutil.GetRangeInBranch(options.git_dir, options.branch) + upstream_commit = gitutil.GetUpstream(options.git_dir, options.branch) + series = patchstream.GetMetaDataForList(upstream_commit, options.git_dir, + 1) + # Conflicting tags are not a problem for buildman, since it does not use + # them. For example, Series-version is not useful for buildman. On the + # other hand conflicting tags will cause an error. So allow later tags + # to overwrite earlier ones. + series.allow_overwrite = True + series = patchstream.GetMetaDataForList(range_expr, options.git_dir, None, + series) + + # By default we have one thread per CPU. But if there are not enough jobs + # we can have fewer threads and use a high '-j' value for make. + if not options.threads: + options.threads = min(multiprocessing.cpu_count(), len(selected)) + if not options.jobs: + options.jobs = max(1, (multiprocessing.cpu_count() + + len(selected) - 1) / len(selected)) + + if not options.step: + options.step = len(series.commits) - 1 + + # Create a new builder with the selected options + output_dir = os.path.join(options.output_dir, options.branch) + builder = Builder(toolchains, output_dir, options.git_dir, + options.threads, options.jobs, checkout=True, + show_unknown=options.show_unknown, step=options.step) + builder.force_config_on_failure = not options.quick + + # For a dry run, just show our actions as a sanity check + if options.dry_run: + ShowActions(series, why_selected, selected, builder, options) + else: + builder.force_build = options.force_build + + # Work out which boards to build + board_selected = boards.GetSelectedDict() + + print GetActionSummary(options.summary, count, board_selected, options) + + if options.summary: + # We can't show function sizes without board details at present + if options.show_bloat: + options.show_detail = True + builder.ShowSummary(series.commits, board_selected, + options.show_errors, options.show_sizes, + options.show_detail, options.show_bloat) + else: + builder.BuildBoards(series.commits, board_selected, + options.show_errors, options.keep_outputs) diff --git a/qemu/roms/u-boot/tools/buildman/test.py b/qemu/roms/u-boot/tools/buildman/test.py new file mode 100644 index 000000000..068784a30 --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/test.py @@ -0,0 +1,169 @@ +# +# Copyright (c) 2012 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import os +import shutil +import sys +import tempfile +import time +import unittest + +# Bring in the patman libraries +our_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(our_path, '../patman')) + +import board +import bsettings +import builder +import control +import command +import commit +import toolchain + +errors = [ + '''main.c: In function 'main_loop': +main.c:260:6: warning: unused variable 'joe' [-Wunused-variable] +''', + '''main.c: In function 'main_loop': +main.c:295:2: error: 'fred' undeclared (first use in this function) +main.c:295:2: note: each undeclared identifier is reported only once for each function it appears in +make[1]: *** [main.o] Error 1 +make: *** [common/libcommon.o] Error 2 +Make failed +''', + '''main.c: In function 'main_loop': +main.c:280:6: warning: unused variable 'mary' [-Wunused-variable] +''', + '''powerpc-linux-ld: warning: dot moved backwards before `.bss' +powerpc-linux-ld: warning: dot moved backwards before `.bss' +powerpc-linux-ld: u-boot: section .text lma 0xfffc0000 overlaps previous sections +powerpc-linux-ld: u-boot: section .rodata lma 0xfffef3ec overlaps previous sections +powerpc-linux-ld: u-boot: section .reloc lma 0xffffa400 overlaps previous sections +powerpc-linux-ld: u-boot: section .data lma 0xffffcd38 overlaps previous sections +powerpc-linux-ld: u-boot: section .u_boot_cmd lma 0xffffeb40 overlaps previous sections +powerpc-linux-ld: u-boot: section .bootpg lma 0xfffff198 overlaps previous sections +''' +] + + +# hash, subject, return code, list of errors/warnings +commits = [ + ['1234', 'upstream/master, ok', 0, []], + ['5678', 'Second commit, a warning', 0, errors[0:1]], + ['9012', 'Third commit, error', 1, errors[0:2]], + ['3456', 'Fourth commit, warning', 0, [errors[0], errors[2]]], + ['7890', 'Fifth commit, link errors', 1, [errors[0], errors[3]]], + ['abcd', 'Sixth commit, fixes all errors', 0, []] +] + +boards = [ + ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 1', 'board0', ''], + ['Active', 'arm', 'armv7', '', 'Tester', 'ARM Board 2', 'board1', ''], + ['Active', 'powerpc', 'powerpc', '', 'Tester', 'PowerPC board 1', 'board2', ''], + ['Active', 'powerpc', 'mpc5xx', '', 'Tester', 'PowerPC board 2', 'board3', ''], + ['Active', 'sandbox', 'sandbox', '', 'Tester', 'Sandbox board', 'board4', ''], +] + +class Options: + """Class that holds build options""" + pass + +class TestBuild(unittest.TestCase): + """Test buildman + + TODO: Write tests for the rest of the functionality + """ + def setUp(self): + # Set up commits to build + self.commits = [] + sequence = 0 + for commit_info in commits: + comm = commit.Commit(commit_info[0]) + comm.subject = commit_info[1] + comm.return_code = commit_info[2] + comm.error_list = commit_info[3] + comm.sequence = sequence + sequence += 1 + self.commits.append(comm) + + # Set up boards to build + self.boards = board.Boards() + for brd in boards: + self.boards.AddBoard(board.Board(*brd)) + self.boards.SelectBoards([]) + + # Set up the toolchains + bsettings.Setup() + self.toolchains = toolchain.Toolchains() + self.toolchains.Add('arm-linux-gcc', test=False) + self.toolchains.Add('sparc-linux-gcc', test=False) + self.toolchains.Add('powerpc-linux-gcc', test=False) + self.toolchains.Add('gcc', test=False) + + def Make(self, commit, brd, stage, *args, **kwargs): + result = command.CommandResult() + boardnum = int(brd.target[-1]) + result.return_code = 0 + result.stderr = '' + result.stdout = ('This is the test output for board %s, commit %s' % + (brd.target, commit.hash)) + if boardnum >= 1 and boardnum >= commit.sequence: + result.return_code = commit.return_code + result.stderr = ''.join(commit.error_list) + if stage == 'build': + target_dir = None + for arg in args: + if arg.startswith('O='): + target_dir = arg[2:] + + if not os.path.isdir(target_dir): + os.mkdir(target_dir) + #time.sleep(.2 + boardnum * .2) + + result.combined = result.stdout + result.stderr + return result + + def testBasic(self): + """Test basic builder operation""" + output_dir = tempfile.mkdtemp() + if not os.path.isdir(output_dir): + os.mkdir(output_dir) + build = builder.Builder(self.toolchains, output_dir, None, 1, 2, + checkout=False, show_unknown=False) + build.do_make = self.Make + board_selected = self.boards.GetSelectedDict() + + #build.BuildCommits(self.commits, board_selected, False) + build.BuildBoards(self.commits, board_selected, False, False) + build.ShowSummary(self.commits, board_selected, True, False, + False, False) + + def _testGit(self): + """Test basic builder operation by building a branch""" + base_dir = tempfile.mkdtemp() + if not os.path.isdir(base_dir): + os.mkdir(base_dir) + options = Options() + options.git = os.getcwd() + options.summary = False + options.jobs = None + options.dry_run = False + #options.git = os.path.join(base_dir, 'repo') + options.branch = 'test-buildman' + options.force_build = False + options.list_tool_chains = False + options.count = -1 + options.git_dir = None + options.threads = None + options.show_unknown = False + options.quick = False + options.show_errors = False + options.keep_outputs = False + args = ['tegra20'] + control.DoBuildman(options, args) + +if __name__ == "__main__": + unittest.main() diff --git a/qemu/roms/u-boot/tools/buildman/toolchain.py b/qemu/roms/u-boot/tools/buildman/toolchain.py new file mode 100644 index 000000000..b64338680 --- /dev/null +++ b/qemu/roms/u-boot/tools/buildman/toolchain.py @@ -0,0 +1,247 @@ +# Copyright (c) 2012 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import re +import glob +import os + +import bsettings +import command + +class Toolchain: + """A single toolchain + + Public members: + gcc: Full path to C compiler + path: Directory path containing C compiler + cross: Cross compile string, e.g. 'arm-linux-' + arch: Architecture of toolchain as determined from the first + component of the filename. E.g. arm-linux-gcc becomes arm + """ + + def __init__(self, fname, test, verbose=False): + """Create a new toolchain object. + + Args: + fname: Filename of the gcc component + test: True to run the toolchain to test it + """ + self.gcc = fname + self.path = os.path.dirname(fname) + self.cross = os.path.basename(fname)[:-3] + pos = self.cross.find('-') + self.arch = self.cross[:pos] if pos != -1 else 'sandbox' + + env = self.MakeEnvironment() + + # As a basic sanity check, run the C compiler with --version + cmd = [fname, '--version'] + if test: + result = command.RunPipe([cmd], capture=True, env=env, + raise_on_error=False) + self.ok = result.return_code == 0 + if verbose: + print 'Tool chain test: ', + if self.ok: + print 'OK' + else: + print 'BAD' + print 'Command: ', cmd + print result.stdout + print result.stderr + else: + self.ok = True + self.priority = self.GetPriority(fname) + + def GetPriority(self, fname): + """Return the priority of the toolchain. + + Toolchains are ranked according to their suitability by their + filename prefix. + + Args: + fname: Filename of toolchain + Returns: + Priority of toolchain, 0=highest, 20=lowest. + """ + priority_list = ['-elf', '-unknown-linux-gnu', '-linux', '-elf', + '-none-linux-gnueabi', '-uclinux', '-none-eabi', + '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux'] + for prio in range(len(priority_list)): + if priority_list[prio] in fname: + return prio + return prio + + def MakeEnvironment(self): + """Returns an environment for using the toolchain. + + Thie takes the current environment, adds CROSS_COMPILE and + augments PATH so that the toolchain will operate correctly. + """ + env = dict(os.environ) + env['CROSS_COMPILE'] = self.cross + env['PATH'] += (':' + self.path) + return env + + +class Toolchains: + """Manage a list of toolchains for building U-Boot + + We select one toolchain for each architecture type + + Public members: + toolchains: Dict of Toolchain objects, keyed by architecture name + paths: List of paths to check for toolchains (may contain wildcards) + """ + + def __init__(self): + self.toolchains = {} + self.paths = [] + toolchains = bsettings.GetItems('toolchain') + if not toolchains: + print ("Warning: No tool chains - please add a [toolchain] section" + " to your buildman config file %s. See README for details" % + config_fname) + + for name, value in toolchains: + if '*' in value: + self.paths += glob.glob(value) + else: + self.paths.append(value) + self._make_flags = dict(bsettings.GetItems('make-flags')) + + def Add(self, fname, test=True, verbose=False): + """Add a toolchain to our list + + We select the given toolchain as our preferred one for its + architecture if it is a higher priority than the others. + + Args: + fname: Filename of toolchain's gcc driver + test: True to run the toolchain to test it + """ + toolchain = Toolchain(fname, test, verbose) + add_it = toolchain.ok + if toolchain.arch in self.toolchains: + add_it = (toolchain.priority < + self.toolchains[toolchain.arch].priority) + if add_it: + self.toolchains[toolchain.arch] = toolchain + + def Scan(self, verbose): + """Scan for available toolchains and select the best for each arch. + + We look for all the toolchains we can file, figure out the + architecture for each, and whether it works. Then we select the + highest priority toolchain for each arch. + + Args: + verbose: True to print out progress information + """ + if verbose: print 'Scanning for tool chains' + for path in self.paths: + if verbose: print " - scanning path '%s'" % path + for subdir in ['.', 'bin', 'usr/bin']: + dirname = os.path.join(path, subdir) + if verbose: print " - looking in '%s'" % dirname + for fname in glob.glob(dirname + '/*gcc'): + if verbose: print " - found '%s'" % fname + self.Add(fname, True, verbose) + + def List(self): + """List out the selected toolchains for each architecture""" + print 'List of available toolchains (%d):' % len(self.toolchains) + if len(self.toolchains): + for key, value in sorted(self.toolchains.iteritems()): + print '%-10s: %s' % (key, value.gcc) + else: + print 'None' + + def Select(self, arch): + """Returns the toolchain for a given architecture + + Args: + args: Name of architecture (e.g. 'arm', 'ppc_8xx') + + returns: + toolchain object, or None if none found + """ + for name, value in bsettings.GetItems('toolchain-alias'): + if arch == name: + arch = value + + if not arch in self.toolchains: + raise ValueError, ("No tool chain found for arch '%s'" % arch) + return self.toolchains[arch] + + def ResolveReferences(self, var_dict, args): + """Resolve variable references in a string + + This converts ${blah} within the string to the value of blah. + This function works recursively. + + Args: + var_dict: Dictionary containing variables and their values + args: String containing make arguments + Returns: + Resolved string + + >>> bsettings.Setup() + >>> tcs = Toolchains() + >>> tcs.Add('fred', False) + >>> var_dict = {'oblique' : 'OBLIQUE', 'first' : 'fi${second}rst', \ + 'second' : '2nd'} + >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set') + 'this=OBLIQUE_set' + >>> tcs.ResolveReferences(var_dict, 'this=${oblique}_set${first}nd') + 'this=OBLIQUE_setfi2ndrstnd' + """ + re_var = re.compile('(\$\{[a-z0-9A-Z]{1,}\})') + + while True: + m = re_var.search(args) + if not m: + break + lookup = m.group(0)[2:-1] + value = var_dict.get(lookup, '') + args = args[:m.start(0)] + value + args[m.end(0):] + return args + + def GetMakeArguments(self, board): + """Returns 'make' arguments for a given board + + The flags are in a section called 'make-flags'. Flags are named + after the target they represent, for example snapper9260=TESTING=1 + will pass TESTING=1 to make when building the snapper9260 board. + + References to other boards can be added in the string also. For + example: + + [make-flags] + at91-boards=ENABLE_AT91_TEST=1 + snapper9260=${at91-boards} BUILD_TAG=442 + snapper9g45=${at91-boards} BUILD_TAG=443 + + This will return 'ENABLE_AT91_TEST=1 BUILD_TAG=442' for snapper9260 + and 'ENABLE_AT91_TEST=1 BUILD_TAG=443' for snapper9g45. + + A special 'target' variable is set to the board target. + + Args: + board: Board object for the board to check. + Returns: + 'make' flags for that board, or '' if none + """ + self._make_flags['target'] = board.target + arg_str = self.ResolveReferences(self._make_flags, + self._make_flags.get(board.target, '')) + args = arg_str.split(' ') + i = 0 + while i < len(args): + if not args[i]: + del args[i] + else: + i += 1 + return args diff --git a/qemu/roms/u-boot/tools/crc32.c b/qemu/roms/u-boot/tools/crc32.c new file mode 100644 index 000000000..aed7112f6 --- /dev/null +++ b/qemu/roms/u-boot/tools/crc32.c @@ -0,0 +1 @@ +#include "../lib/crc32.c" diff --git a/qemu/roms/u-boot/tools/default_image.c b/qemu/roms/u-boot/tools/default_image.c new file mode 100644 index 000000000..0a0792e50 --- /dev/null +++ b/qemu/roms/u-boot/tools/default_image.c @@ -0,0 +1,194 @@ +/* + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2004 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * + * Updated-by: Prafulla Wadaskar <prafulla@marvell.com> + * default_image specific code abstracted from mkimage.c + * some functions added to address abstraction + * + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include <image.h> +#include <u-boot/crc.h> + +static image_header_t header; + +static int image_check_image_types(uint8_t type) +{ + if (((type > IH_TYPE_INVALID) && (type < IH_TYPE_FLATDT)) || + (type == IH_TYPE_KERNEL_NOLOAD)) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +} + +static int image_check_params(struct image_tool_params *params) +{ + return ((params->dflag && (params->fflag || params->lflag)) || + (params->fflag && (params->dflag || params->lflag)) || + (params->lflag && (params->dflag || params->fflag))); +} + +static int image_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + uint32_t len; + const unsigned char *data; + uint32_t checksum; + image_header_t header; + image_header_t *hdr = &header; + + /* + * create copy of header so that we can blank out the + * checksum field for checking - this can't be done + * on the PROT_READ mapped data. + */ + memcpy(hdr, ptr, sizeof(image_header_t)); + + if (be32_to_cpu(hdr->ih_magic) != IH_MAGIC) { + fprintf(stderr, + "%s: Bad Magic Number: \"%s\" is no valid image\n", + params->cmdname, params->imagefile); + return -FDT_ERR_BADMAGIC; + } + + data = (const unsigned char *)hdr; + len = sizeof(image_header_t); + + checksum = be32_to_cpu(hdr->ih_hcrc); + hdr->ih_hcrc = cpu_to_be32(0); /* clear for re-calculation */ + + if (crc32(0, data, len) != checksum) { + fprintf(stderr, + "%s: ERROR: \"%s\" has bad header checksum!\n", + params->cmdname, params->imagefile); + return -FDT_ERR_BADSTATE; + } + + data = (const unsigned char *)ptr + sizeof(image_header_t); + len = image_size - sizeof(image_header_t) ; + + checksum = be32_to_cpu(hdr->ih_dcrc); + if (crc32(0, data, len) != checksum) { + fprintf(stderr, + "%s: ERROR: \"%s\" has corrupted data!\n", + params->cmdname, params->imagefile); + return -FDT_ERR_BADSTRUCTURE; + } + return 0; +} + +static void image_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + uint32_t checksum; + + image_header_t * hdr = (image_header_t *)ptr; + + checksum = crc32(0, + (const unsigned char *)(ptr + + sizeof(image_header_t)), + sbuf->st_size - sizeof(image_header_t)); + + /* Build new header */ + image_set_magic(hdr, IH_MAGIC); + image_set_time(hdr, sbuf->st_mtime); + image_set_size(hdr, sbuf->st_size - sizeof(image_header_t)); + image_set_load(hdr, params->addr); + image_set_ep(hdr, params->ep); + image_set_dcrc(hdr, checksum); + image_set_os(hdr, params->os); + image_set_arch(hdr, params->arch); + image_set_type(hdr, params->type); + image_set_comp(hdr, params->comp); + + image_set_name(hdr, params->imagename); + + checksum = crc32(0, (const unsigned char *)hdr, + sizeof(image_header_t)); + + image_set_hcrc(hdr, checksum); +} + +static int image_save_datafile(struct image_tool_params *params, + ulong file_data, ulong file_len) +{ + int dfd; + const char *datafile = params->outfile; + + dfd = open(datafile, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + S_IRUSR | S_IWUSR); + if (dfd < 0) { + fprintf(stderr, "%s: Can't open \"%s\": %s\n", + params->cmdname, datafile, strerror(errno)); + return -1; + } + + if (write(dfd, (void *)file_data, file_len) != (ssize_t)file_len) { + fprintf(stderr, "%s: Write error on \"%s\": %s\n", + params->cmdname, datafile, strerror(errno)); + close(dfd); + return -1; + } + + close(dfd); + + return 0; +} + +static int image_extract_datafile(void *ptr, struct image_tool_params *params) +{ + const image_header_t *hdr = (const image_header_t *)ptr; + ulong file_data; + ulong file_len; + + if (image_check_type(hdr, IH_TYPE_MULTI)) { + ulong idx = params->pflag; + ulong count; + + /* get the number of data files present in the image */ + count = image_multi_count(hdr); + + /* retrieve the "data file" at the idx position */ + image_multi_getimg(hdr, idx, &file_data, &file_len); + + if ((file_len == 0) || (idx >= count)) { + fprintf(stderr, "%s: No such data file %ld in \"%s\"\n", + params->cmdname, idx, params->imagefile); + return -1; + } + } else { + file_data = image_get_data(hdr); + file_len = image_get_size(hdr); + } + + /* save the "data file" into the file system */ + return image_save_datafile(params, file_data, file_len); +} + +/* + * Default image type parameters definition + */ +static struct image_type_params defimage_params = { + .name = "Default Image support", + .header_size = sizeof(image_header_t), + .hdr = (void*)&header, + .check_image_type = image_check_image_types, + .verify_header = image_verify_header, + .print_header = image_print_contents, + .set_header = image_set_header, + .extract_datafile = image_extract_datafile, + .check_params = image_check_params, +}; + +void init_default_image_type(void) +{ + register_image_type(&defimage_params); +} diff --git a/qemu/roms/u-boot/tools/dumpimage.c b/qemu/roms/u-boot/tools/dumpimage.c new file mode 100644 index 000000000..542ee2821 --- /dev/null +++ b/qemu/roms/u-boot/tools/dumpimage.c @@ -0,0 +1,305 @@ +/* + * Based on mkimage.c. + * + * Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "dumpimage.h" +#include <image.h> +#include <version.h> + +static void usage(void); + +/* image_type_params linked list to maintain registered image types supports */ +static struct image_type_params *dumpimage_tparams; + +/* parameters initialized by core will be used by the image type code */ +static struct image_tool_params params = { + .type = IH_TYPE_KERNEL, +}; + +/** + * dumpimage_register() - register respective image generation/list support + * + * the input struct image_type_params is checked and appended to the link + * list, if the input structure is already registered, issue an error + * + * @tparams: Image type parameters + */ +static void dumpimage_register(struct image_type_params *tparams) +{ + struct image_type_params **tp; + + if (!tparams) { + fprintf(stderr, "%s: %s: Null input\n", params.cmdname, + __func__); + exit(EXIT_FAILURE); + } + + /* scan the linked list, check for registry and point the last one */ + for (tp = &dumpimage_tparams; *tp != NULL; tp = &(*tp)->next) { + if (!strcmp((*tp)->name, tparams->name)) { + fprintf(stderr, "%s: %s already registered\n", + params.cmdname, tparams->name); + return; + } + } + + /* add input struct entry at the end of link list */ + *tp = tparams; + /* mark input entry as last entry in the link list */ + tparams->next = NULL; + + debug("Registered %s\n", tparams->name); +} + +/** + * dumpimage_get_type() - find the image type params for a given image type + * + * Scan all registered image types and check the input type_id for each + * supported image type + * + * @return respective image_type_params pointer. If the input type is not + * supported by any of registered image types, returns NULL + */ +static struct image_type_params *dumpimage_get_type(int type) +{ + struct image_type_params *curr; + + for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) { + if (curr->check_image_type) { + if (!curr->check_image_type(type)) + return curr; + } + } + return NULL; +} + +/* + * dumpimage_verify_print_header() - verifies the image header + * + * Scan registered image types and verify the image_header for each + * supported image type. If verification is successful, this prints + * the respective header. + * + * @return 0 on success, negative if input image format does not match with + * any of supported image types + */ +static int dumpimage_verify_print_header(void *ptr, struct stat *sbuf) +{ + int retval = -1; + struct image_type_params *curr; + + for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) { + if (curr->verify_header) { + retval = curr->verify_header((unsigned char *)ptr, + sbuf->st_size, ¶ms); + if (retval != 0) + continue; + /* + * Print the image information if verify is + * successful + */ + if (curr->print_header) { + curr->print_header(ptr); + } else { + fprintf(stderr, + "%s: print_header undefined for %s\n", + params.cmdname, curr->name); + } + break; + } + } + + return retval; +} + +/* + * dumpimage_extract_datafile - + * + * It scans all registered image types, + * verifies image_header for each supported image type + * if verification is successful, it extracts the desired file, + * indexed by pflag, from the image + * + * returns negative if input image format does not match with any of + * supported image types + */ +static int dumpimage_extract_datafile(void *ptr, struct stat *sbuf) +{ + int retval = -1; + struct image_type_params *curr; + + for (curr = dumpimage_tparams; curr != NULL; curr = curr->next) { + if (curr->verify_header) { + retval = curr->verify_header((unsigned char *)ptr, + sbuf->st_size, ¶ms); + if (retval != 0) + continue; + /* + * Extract the file from the image + * if verify is successful + */ + if (curr->extract_datafile) { + curr->extract_datafile(ptr, ¶ms); + } else { + fprintf(stderr, + "%s: extract_datafile undefined for %s\n", + params.cmdname, curr->name); + break; + } + } + } + + return retval; +} + +int main(int argc, char **argv) +{ + int opt; + int ifd = -1; + struct stat sbuf; + char *ptr; + int retval = 0; + struct image_type_params *tparams = NULL; + + /* Init all image generation/list support */ + register_image_tool(dumpimage_register); + + params.cmdname = *argv; + + while ((opt = getopt(argc, argv, "li:o:p:V")) != -1) { + switch (opt) { + case 'l': + params.lflag = 1; + break; + case 'i': + params.imagefile = optarg; + params.iflag = 1; + break; + case 'o': + params.outfile = optarg; + break; + case 'p': + params.pflag = strtoul(optarg, &ptr, 10); + if (*ptr) { + fprintf(stderr, + "%s: invalid file position %s\n", + params.cmdname, *argv); + exit(EXIT_FAILURE); + } + break; + case 'V': + printf("dumpimage version %s\n", PLAIN_VERSION); + exit(EXIT_SUCCESS); + default: + usage(); + } + } + + if (optind >= argc) + usage(); + + /* set tparams as per input type_id */ + tparams = dumpimage_get_type(params.type); + if (tparams == NULL) { + fprintf(stderr, "%s: unsupported type %s\n", + params.cmdname, genimg_get_type_name(params.type)); + exit(EXIT_FAILURE); + } + + /* + * check the passed arguments parameters meets the requirements + * as per image type to be generated/listed + */ + if (tparams->check_params) { + if (tparams->check_params(¶ms)) + usage(); + } + + if (params.iflag) + params.datafile = argv[optind]; + else + params.imagefile = argv[optind]; + if (!params.outfile) + params.outfile = params.datafile; + + ifd = open(params.imagefile, O_RDONLY|O_BINARY); + if (ifd < 0) { + fprintf(stderr, "%s: Can't open \"%s\": %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit(EXIT_FAILURE); + } + + if (params.lflag || params.iflag) { + if (fstat(ifd, &sbuf) < 0) { + fprintf(stderr, "%s: Can't stat \"%s\": %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit(EXIT_FAILURE); + } + + if ((unsigned)sbuf.st_size < tparams->header_size) { + fprintf(stderr, + "%s: Bad size: \"%s\" is not valid image\n", + params.cmdname, params.imagefile); + exit(EXIT_FAILURE); + } + + ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0); + if (ptr == MAP_FAILED) { + fprintf(stderr, "%s: Can't read \"%s\": %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit(EXIT_FAILURE); + } + + /* + * Both calls bellow scan through dumpimage registry for all + * supported image types and verify the input image file + * header for match + */ + if (params.iflag) { + /* + * Extract the data files from within the matched + * image type. Returns the error code if not matched + */ + retval = dumpimage_extract_datafile(ptr, &sbuf); + } else { + /* + * Print the image information for matched image type + * Returns the error code if not matched + */ + retval = dumpimage_verify_print_header(ptr, &sbuf); + } + + (void)munmap((void *)ptr, sbuf.st_size); + (void)close(ifd); + + return retval; + } + + (void)close(ifd); + + return EXIT_SUCCESS; +} + +static void usage(void) +{ + fprintf(stderr, "Usage: %s -l image\n" + " -l ==> list image header information\n", + params.cmdname); + fprintf(stderr, + " %s -i image [-p position] [-o outfile] data_file\n" + " -i ==> extract from the 'image' a specific 'data_file'" + ", indexed by 'position' (starting at 0)\n", + params.cmdname); + fprintf(stderr, + " %s -V ==> print version information and exit\n", + params.cmdname); + + exit(EXIT_FAILURE); +} diff --git a/qemu/roms/u-boot/tools/dumpimage.h b/qemu/roms/u-boot/tools/dumpimage.h new file mode 100644 index 000000000..d78523ded --- /dev/null +++ b/qemu/roms/u-boot/tools/dumpimage.h @@ -0,0 +1,33 @@ +/* + * Based on mkimage.c. + * + * Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _DUMPIMAGE_H_ +#define _DUMPIMAGE_H_ + +#include "os_support.h" +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> +#include <sha1.h> +#include "fdt_host.h" +#include "imagetool.h" + +#undef DUMPIMAGE_DEBUG + +#ifdef DUMPIMAGE_DEBUG +#define debug(fmt, args...) printf(fmt, ##args) +#else +#define debug(fmt, args...) +#endif /* DUMPIMAGE_DEBUG */ + +#endif /* _DUMPIMAGE_H_ */ diff --git a/qemu/roms/u-boot/tools/easylogo/Makefile b/qemu/roms/u-boot/tools/easylogo/Makefile new file mode 100644 index 000000000..10aba2ba6 --- /dev/null +++ b/qemu/roms/u-boot/tools/easylogo/Makefile @@ -0,0 +1,3 @@ +hostprogs-y := easylogo + +always := $(hostprogs-y) diff --git a/qemu/roms/u-boot/tools/easylogo/easylogo.c b/qemu/roms/u-boot/tools/easylogo/easylogo.c new file mode 100644 index 000000000..4ba86bf76 --- /dev/null +++ b/qemu/roms/u-boot/tools/easylogo/easylogo.c @@ -0,0 +1,610 @@ +/* +** Easylogo TGA->header converter +** ============================== +** (C) 2000 by Paolo Scaffardi (arsenio@tin.it) +** AIRVENT SAM s.p.a - RIMINI(ITALY) +** (C) 2007-2008 Mike Frysinger <vapier@gentoo.org> +** +** This is still under construction! +*/ + +#include <errno.h> +#include <getopt.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> + +#pragma pack(1) + +/*#define ENABLE_ASCII_BANNERS */ + +typedef struct { + unsigned char id; + unsigned char ColorMapType; + unsigned char ImageTypeCode; + unsigned short ColorMapOrigin; + unsigned short ColorMapLenght; + unsigned char ColorMapEntrySize; + unsigned short ImageXOrigin; + unsigned short ImageYOrigin; + unsigned short ImageWidth; + unsigned short ImageHeight; + unsigned char ImagePixelSize; + unsigned char ImageDescriptorByte; +} tga_header_t; + +typedef struct { + unsigned char r, g, b; +} rgb_t; + +typedef struct { + unsigned char b, g, r; +} bgr_t; + +typedef struct { + unsigned char Cb, y1, Cr, y2; +} yuyv_t; + +typedef struct { + void *data, *palette; + int width, height, pixels, bpp, pixel_size, size, palette_size, yuyv; +} image_t; + +void *xmalloc (size_t size) +{ + void *ret = malloc (size); + if (!ret) { + fprintf (stderr, "\nerror: malloc(%zu) failed: %s", + size, strerror(errno)); + exit (1); + } + return ret; +} + +void StringUpperCase (char *str) +{ + int count = strlen (str); + char c; + + while (count--) { + c = *str; + if ((c >= 'a') && (c <= 'z')) + *str = 'A' + (c - 'a'); + str++; + } +} + +void StringLowerCase (char *str) +{ + int count = strlen (str); + char c; + + while (count--) { + c = *str; + if ((c >= 'A') && (c <= 'Z')) + *str = 'a' + (c - 'A'); + str++; + } +} +void pixel_rgb_to_yuyv (rgb_t * rgb_pixel, yuyv_t * yuyv_pixel) +{ + unsigned int pR, pG, pB; + + /* Transform (0-255) components to (0-100) */ + pR = rgb_pixel->r * 100 / 255; + pG = rgb_pixel->g * 100 / 255; + pB = rgb_pixel->b * 100 / 255; + + /* Calculate YUV values (0-255) from RGB beetween 0-100 */ + yuyv_pixel->y1 = yuyv_pixel->y2 = 209 * (pR + pG + pB) / 300 + 16; + yuyv_pixel->Cb = pB - (pR / 4) - (pG * 3 / 4) + 128; + yuyv_pixel->Cr = pR - (pG * 3 / 4) - (pB / 4) + 128; + + return; +} + +void printlogo_rgb (rgb_t * data, int w, int h) +{ + int x, y; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++, data++) + if ((data->r < + 30) /*&&(data->g == 0)&&(data->b == 0) */ ) + printf (" "); + else + printf ("X"); + printf ("\n"); + } +} + +void printlogo_yuyv (unsigned short *data, int w, int h) +{ + int x, y; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++, data++) + if (*data == 0x1080) /* Because of inverted on i386! */ + printf (" "); + else + printf ("X"); + printf ("\n"); + } +} + +static inline unsigned short le16_to_cpu (unsigned short val) +{ + union { + unsigned char pval[2]; + unsigned short val; + } swapped; + + swapped.val = val; + return (swapped.pval[1] << 8) + swapped.pval[0]; +} + +int image_load_tga (image_t * image, char *filename) +{ + FILE *file; + tga_header_t header; + int i; + unsigned char app; + rgb_t *p; + + if ((file = fopen (filename, "rb")) == NULL) + return -1; + + fread (&header, sizeof (header), 1, file); + + /* byte swap: tga is little endian, host is ??? */ + header.ColorMapOrigin = le16_to_cpu (header.ColorMapOrigin); + header.ColorMapLenght = le16_to_cpu (header.ColorMapLenght); + header.ImageXOrigin = le16_to_cpu (header.ImageXOrigin); + header.ImageYOrigin = le16_to_cpu (header.ImageYOrigin); + header.ImageWidth = le16_to_cpu (header.ImageWidth); + header.ImageHeight = le16_to_cpu (header.ImageHeight); + + image->width = header.ImageWidth; + image->height = header.ImageHeight; + + switch (header.ImageTypeCode) { + case 2: /* Uncompressed RGB */ + image->yuyv = 0; + image->palette_size = 0; + image->palette = NULL; + break; + + default: + printf ("Format not supported!\n"); + return -1; + } + + image->bpp = header.ImagePixelSize; + image->pixel_size = ((image->bpp - 1) / 8) + 1; + image->pixels = image->width * image->height; + image->size = image->pixels * image->pixel_size; + image->data = xmalloc (image->size); + + if (image->bpp != 24) { + printf ("Bpp not supported: %d!\n", image->bpp); + return -1; + } + + fread (image->data, image->size, 1, file); + +/* Swapping R and B values */ + + p = image->data; + for (i = 0; i < image->pixels; i++, p++) { + app = p->r; + p->r = p->b; + p->b = app; + } + +/* Swapping image */ + + if (!(header.ImageDescriptorByte & 0x20)) { + unsigned char *temp = xmalloc (image->size); + int linesize = image->pixel_size * image->width; + void *dest = image->data, + *source = temp + image->size - linesize; + + printf ("S"); + if (temp == NULL) { + printf ("Cannot alloc temp buffer!\n"); + return -1; + } + + memcpy (temp, image->data, image->size); + for (i = 0; i < image->height; + i++, dest += linesize, source -= linesize) + memcpy (dest, source, linesize); + + free (temp); + } +#ifdef ENABLE_ASCII_BANNERS + printlogo_rgb (image->data, image->width, image->height); +#endif + + fclose (file); + return 0; +} + +void image_free (image_t * image) +{ + free (image->data); + free (image->palette); +} + +int image_rgb_to_yuyv (image_t * rgb_image, image_t * yuyv_image) +{ + rgb_t *rgb_ptr = (rgb_t *) rgb_image->data; + yuyv_t yuyv; + unsigned short *dest; + int count = 0; + + yuyv_image->pixel_size = 2; + yuyv_image->bpp = 16; + yuyv_image->yuyv = 1; + yuyv_image->width = rgb_image->width; + yuyv_image->height = rgb_image->height; + yuyv_image->pixels = yuyv_image->width * yuyv_image->height; + yuyv_image->size = yuyv_image->pixels * yuyv_image->pixel_size; + dest = (unsigned short *) (yuyv_image->data = + xmalloc (yuyv_image->size)); + yuyv_image->palette = 0; + yuyv_image->palette_size = 0; + + while ((count++) < rgb_image->pixels) { + pixel_rgb_to_yuyv (rgb_ptr++, &yuyv); + + if ((count & 1) == 0) /* Was == 0 */ + memcpy (dest, ((void *) &yuyv) + 2, sizeof (short)); + else + memcpy (dest, (void *) &yuyv, sizeof (short)); + + dest++; + } + +#ifdef ENABLE_ASCII_BANNERS + printlogo_yuyv (yuyv_image->data, yuyv_image->width, + yuyv_image->height); +#endif + return 0; +} + +int image_rgb888_to_rgb565(image_t *rgb888_image, image_t *rgb565_image) +{ + rgb_t *rgb_ptr = (rgb_t *) rgb888_image->data; + unsigned short *dest; + int count = 0; + + rgb565_image->pixel_size = 2; + rgb565_image->bpp = 16; + rgb565_image->yuyv = 0; + rgb565_image->width = rgb888_image->width; + rgb565_image->height = rgb888_image->height; + rgb565_image->pixels = rgb565_image->width * rgb565_image->height; + rgb565_image->size = rgb565_image->pixels * rgb565_image->pixel_size; + dest = (unsigned short *) (rgb565_image->data = + xmalloc(rgb565_image->size)); + rgb565_image->palette = 0; + rgb565_image->palette_size = 0; + + while ((count++) < rgb888_image->pixels) { + + *dest++ = ((rgb_ptr->b & 0xF8) << 8) | + ((rgb_ptr->g & 0xFC) << 3) | + (rgb_ptr->r >> 3); + rgb_ptr++; + } + + return 0; +} + +enum comp_t { + COMP_NONE, + COMP_GZIP, + COMP_LZMA, +}; +static enum comp_t compression = COMP_NONE; +static bool bss_storage = false; + +int image_save_header (image_t * image, char *filename, char *varname) +{ + FILE *file = fopen (filename, "w"); + char app[256], str[256] = "", def_name[64]; + int count = image->size, col = 0; + unsigned char *dataptr = image->data; + + if (file == NULL) + return -1; + + /* Author information */ + fprintf (file, + "/*\n * Generated by EasyLogo, (C) 2000 by Paolo Scaffardi\n *\n"); + fprintf (file, + " * To use this, include it and call: easylogo_plot(screen,&%s, width,x,y)\n *\n", + varname); + fprintf (file, + " * Where:\t'screen'\tis the pointer to the frame buffer\n"); + fprintf (file, " *\t\t'width'\tis the screen width\n"); + fprintf (file, " *\t\t'x'\t\tis the horizontal position\n"); + fprintf (file, " *\t\t'y'\t\tis the vertical position\n */\n\n"); + + /* image compress */ + if (compression != COMP_NONE) { + const char *errstr = NULL; + unsigned char *compressed; + const char *comp_name; + struct stat st; + FILE *compfp; + size_t filename_len = strlen(filename); + char *compfilename = xmalloc(filename_len + 20); + char *compcmd = xmalloc(filename_len + 50); + + sprintf(compfilename, "%s.bin", filename); + switch (compression) { + case COMP_GZIP: + strcpy(compcmd, "gzip"); + comp_name = "GZIP"; + break; + case COMP_LZMA: + strcpy(compcmd, "lzma"); + comp_name = "LZMA"; + break; + default: + errstr = "\nerror: unknown compression method"; + goto done; + } + strcat(compcmd, " > "); + strcat(compcmd, compfilename); + compfp = popen(compcmd, "w"); + if (!compfp) { + errstr = "\nerror: popen() failed"; + goto done; + } + if (fwrite(image->data, image->size, 1, compfp) != 1) { + errstr = "\nerror: writing data to gzip failed"; + goto done; + } + if (pclose(compfp)) { + errstr = "\nerror: gzip process failed"; + goto done; + } + + compfp = fopen(compfilename, "r"); + if (!compfp) { + errstr = "\nerror: open() on gzip data failed"; + goto done; + } + if (stat(compfilename, &st)) { + errstr = "\nerror: stat() on gzip file failed"; + goto done; + } + compressed = xmalloc(st.st_size); + if (fread(compressed, st.st_size, 1, compfp) != 1) { + errstr = "\nerror: reading gzip data failed"; + goto done; + } + fclose(compfp); + + unlink(compfilename); + + dataptr = compressed; + count = st.st_size; + fprintf(file, "#define EASYLOGO_ENABLE_%s %i\n\n", comp_name, count); + if (bss_storage) + fprintf (file, "static unsigned char EASYLOGO_DECOMP_BUFFER[%i];\n\n", image->size); + + done: + free(compfilename); + free(compcmd); + + if (errstr) { + perror (errstr); + return -1; + } + } + + /* Headers */ + fprintf (file, "#include <video_easylogo.h>\n\n"); + /* Macros */ + strcpy (def_name, varname); + StringUpperCase (def_name); + fprintf (file, "#define DEF_%s_WIDTH\t\t%d\n", def_name, + image->width); + fprintf (file, "#define DEF_%s_HEIGHT\t\t%d\n", def_name, + image->height); + fprintf (file, "#define DEF_%s_PIXELS\t\t%d\n", def_name, + image->pixels); + fprintf (file, "#define DEF_%s_BPP\t\t%d\n", def_name, image->bpp); + fprintf (file, "#define DEF_%s_PIXEL_SIZE\t%d\n", def_name, + image->pixel_size); + fprintf (file, "#define DEF_%s_SIZE\t\t%d\n\n", def_name, + image->size); + /* Declaration */ + fprintf (file, "unsigned char DEF_%s_DATA[] = {\n", + def_name); + + /* Data */ + while (count) + switch (col) { + case 0: + sprintf (str, " 0x%02x", *dataptr++); + col++; + count--; + break; + + case 16: + fprintf (file, "%s", str); + if (count > 0) + fprintf (file, ","); + fprintf (file, "\n"); + + col = 0; + break; + + default: + strcpy (app, str); + sprintf (str, "%s, 0x%02x", app, *dataptr++); + col++; + count--; + break; + } + + if (col) + fprintf (file, "%s\n", str); + + /* End of declaration */ + fprintf (file, "};\n\n"); + /* Variable */ + fprintf (file, "fastimage_t %s = {\n", varname); + fprintf (file, " DEF_%s_DATA,\n", def_name); + fprintf (file, " DEF_%s_WIDTH,\n", def_name); + fprintf (file, " DEF_%s_HEIGHT,\n", def_name); + fprintf (file, " DEF_%s_BPP,\n", def_name); + fprintf (file, " DEF_%s_PIXEL_SIZE,\n", def_name); + fprintf (file, " DEF_%s_SIZE\n};\n", def_name); + + fclose (file); + + return 0; +} + +#define DEF_FILELEN 256 + +static void usage (int exit_status) +{ + puts ( + "EasyLogo 1.0 (C) 2000 by Paolo Scaffardi\n" + "\n" + "Syntax: easylogo [options] inputfile [outputvar [outputfile]]\n" + "\n" + "Options:\n" + " -r Output RGB888 instead of YUYV\n" + " -s Output RGB565 instead of YUYV\n" + " -g Compress with gzip\n" + " -l Compress with lzma\n" + " -b Preallocate space in bss for decompressing image\n" + " -h Help output\n" + "\n" + "Where: 'inputfile' is the TGA image to load\n" + " 'outputvar' is the variable name to create\n" + " 'outputfile' is the output header file (default is 'inputfile.h')" + ); + exit (exit_status); +} + +int main (int argc, char *argv[]) +{ + int c; + bool use_rgb888 = false; + bool use_rgb565 = false; + char inputfile[DEF_FILELEN], + outputfile[DEF_FILELEN], varname[DEF_FILELEN]; + + image_t rgb888_logo, rgb565_logo, yuyv_logo; + + while ((c = getopt(argc, argv, "hrsglb")) > 0) { + switch (c) { + case 'h': + usage (0); + break; + case 'r': + use_rgb888 = true; + puts("Using 24-bit RGB888 Output Fromat"); + break; + case 's': + use_rgb565 = true; + puts("Using 16-bit RGB565 Output Fromat"); + break; + case 'g': + compression = COMP_GZIP; + puts("Compressing with gzip"); + break; + case 'l': + compression = COMP_LZMA; + puts("Compressing with lzma"); + break; + case 'b': + bss_storage = true; + puts("Preallocating bss space for decompressing image"); + break; + default: + usage (1); + break; + } + } + + c = argc - optind; + if (c > 4 || c < 1) + usage (1); + + strcpy (inputfile, argv[optind]); + + if (c > 1) + strcpy (varname, argv[optind + 1]); + else { + /* transform "input.tga" to just "input" */ + char *dot; + strcpy (varname, inputfile); + dot = strchr (varname, '.'); + if (dot) + *dot = '\0'; + } + + if (c > 2) + strcpy (outputfile, argv[optind + 2]); + else { + /* just append ".h" to input file name */ + strcpy (outputfile, inputfile); + strcat (outputfile, ".h"); + } + + /* Make sure the output is sent as soon as we printf() */ + setbuf(stdout, NULL); + + printf ("Doing '%s' (%s) from '%s'...", + outputfile, varname, inputfile); + + /* Import TGA logo */ + + printf ("L"); + if (image_load_tga(&rgb888_logo, inputfile) < 0) { + printf ("input file not found!\n"); + exit (1); + } + + /* Convert, save, and free the image */ + + if (!use_rgb888 && !use_rgb565) { + printf ("C"); + image_rgb_to_yuyv(&rgb888_logo, &yuyv_logo); + + printf("S"); + image_save_header(&yuyv_logo, outputfile, varname); + image_free(&yuyv_logo); + } else if (use_rgb565) { + printf("C"); + image_rgb888_to_rgb565(&rgb888_logo, &rgb565_logo); + + printf("S"); + image_save_header(&rgb565_logo, outputfile, varname); + image_free(&rgb565_logo); + } else { + printf("S"); + image_save_header(&rgb888_logo, outputfile, varname); + } + + /* Free original image and copy */ + + image_free(&rgb888_logo); + + printf ("\n"); + + return 0; +} diff --git a/qemu/roms/u-boot/tools/easylogo/linux_blackfin.tga b/qemu/roms/u-boot/tools/easylogo/linux_blackfin.tga Binary files differnew file mode 100644 index 000000000..e2bb17b80 --- /dev/null +++ b/qemu/roms/u-boot/tools/easylogo/linux_blackfin.tga diff --git a/qemu/roms/u-boot/tools/easylogo/linux_logo.tga b/qemu/roms/u-boot/tools/easylogo/linux_logo.tga Binary files differnew file mode 100644 index 000000000..ac53def05 --- /dev/null +++ b/qemu/roms/u-boot/tools/easylogo/linux_logo.tga diff --git a/qemu/roms/u-boot/tools/easylogo/runme.sh b/qemu/roms/u-boot/tools/easylogo/runme.sh new file mode 100644 index 000000000..625ebaae1 --- /dev/null +++ b/qemu/roms/u-boot/tools/easylogo/runme.sh @@ -0,0 +1,4 @@ +#!/bin/sh +make +./easylogo linux_logo.tga u_boot_logo video_logo.h +mv video_logo.h ../../include diff --git a/qemu/roms/u-boot/tools/env/.gitignore b/qemu/roms/u-boot/tools/env/.gitignore new file mode 100644 index 000000000..804abacc6 --- /dev/null +++ b/qemu/roms/u-boot/tools/env/.gitignore @@ -0,0 +1,2 @@ +fw_printenv +fw_printenv_unstripped diff --git a/qemu/roms/u-boot/tools/env/Makefile b/qemu/roms/u-boot/tools/env/Makefile new file mode 100644 index 000000000..f5368bc4d --- /dev/null +++ b/qemu/roms/u-boot/tools/env/Makefile @@ -0,0 +1,34 @@ +# +# (C) Copyright 2002-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +# fw_printenv is supposed to run on the target system, which means it should be +# built with cross tools. Although it may look weird, we only replace "HOSTCC" +# with "CC" here for the maximum code reuse of scripts/Makefile.host. +HOSTCC = $(CC) + +# Compile for a hosted environment on the target +HOST_EXTRACFLAGS = $(patsubst -I%,-idirafter%, $(UBOOTINCLUDE)) \ + -idirafter $(srctree)/tools/env \ + -DUSE_HOSTCC \ + -DTEXT_BASE=$(TEXT_BASE) + +ifeq ($(MTD_VERSION),old) +HOST_EXTRACFLAGS += -DMTD_OLD +endif + +always := fw_printenv +hostprogs-y := fw_printenv_unstripped + +fw_printenv_unstripped-objs := fw_env.o fw_env_main.o \ + crc32.o ctype.o linux_string.o \ + env_attr.o env_flags.o aes.o + +quiet_cmd_strip = STRIP $@ + cmd_strip = $(STRIP) -o $@ $< + +$(obj)/fw_printenv: $(obj)/fw_printenv_unstripped FORCE + $(call if_changed,strip) diff --git a/qemu/roms/u-boot/tools/env/README b/qemu/roms/u-boot/tools/env/README new file mode 100644 index 000000000..24e31bc9f --- /dev/null +++ b/qemu/roms/u-boot/tools/env/README @@ -0,0 +1,60 @@ + +This is a demo implementation of a Linux command line tool to access +the U-Boot's environment variables. + +In order to cross-compile fw_printenv, run + make CROSS_COMPILE=<your cross-compiler prefix> env +in the root directory of the U-Boot distribution. For example, + make CROSS_COMPILE=arm-linux- env + +For the run-time utility configuration uncomment the line +#define CONFIG_FILE "/etc/fw_env.config" +in fw_env.h. + +For building against older versions of the MTD headers (meaning before +v2.6.8-rc1) it is required to pass the argument "MTD_VERSION=old" to +make. + +See comments in the fw_env.config file for definitions for the +particular board. + +Configuration can also be done via #defines in the fw_env.h file. The +following lines are relevant: + +#define HAVE_REDUND /* For systems with 2 env sectors */ +#define DEVICE1_NAME "/dev/mtd1" +#define DEVICE2_NAME "/dev/mtd2" +#define DEVICE1_OFFSET 0x0000 +#define ENV1_SIZE 0x4000 +#define DEVICE1_ESIZE 0x4000 +#define DEVICE1_ENVSECTORS 2 +#define DEVICE2_OFFSET 0x0000 +#define ENV2_SIZE 0x4000 +#define DEVICE2_ESIZE 0x4000 +#define DEVICE2_ENVSECTORS 2 + +Un-define HAVE_REDUND, if you want to use the utilities on a system +that does not have support for redundant environment enabled. +If HAVE_REDUND is undefined, DEVICE2_NAME is ignored, +as is ENV2_SIZE and DEVICE2_ESIZE. + +The DEVICEx_NAME constants define which MTD character devices are to +be used to access the environment. + +The DEVICEx_OFFSET constants define the environment offset within the +MTD character device. + +ENVx_SIZE defines the size in bytes taken by the environment, which +may be less then flash sector size, if the environment takes less +then 1 sector. + +DEVICEx_ESIZE defines the size of the first sector in the flash +partition where the environment resides. + +DEVICEx_ENVSECTORS defines the number of sectors that may be used for +this environment instance. On NAND this is used to limit the range +within which bad blocks are skipped, on NOR it is not used. + +To prevent losing changes to the environment and to prevent confusing the MTD +drivers, a lock file at /var/lock/fw_printenv.lock is used to serialize access +to the environment. diff --git a/qemu/roms/u-boot/tools/env/aes.c b/qemu/roms/u-boot/tools/env/aes.c new file mode 100644 index 000000000..9e42679e3 --- /dev/null +++ b/qemu/roms/u-boot/tools/env/aes.c @@ -0,0 +1 @@ +#include "../../lib/aes.c" diff --git a/qemu/roms/u-boot/tools/env/crc32.c b/qemu/roms/u-boot/tools/env/crc32.c new file mode 100644 index 000000000..34f8178e3 --- /dev/null +++ b/qemu/roms/u-boot/tools/env/crc32.c @@ -0,0 +1 @@ +#include "../../lib/crc32.c" diff --git a/qemu/roms/u-boot/tools/env/ctype.c b/qemu/roms/u-boot/tools/env/ctype.c new file mode 100644 index 000000000..21050e937 --- /dev/null +++ b/qemu/roms/u-boot/tools/env/ctype.c @@ -0,0 +1 @@ +#include "../../lib/ctype.c" diff --git a/qemu/roms/u-boot/tools/env/env_attr.c b/qemu/roms/u-boot/tools/env/env_attr.c new file mode 100644 index 000000000..502d4c900 --- /dev/null +++ b/qemu/roms/u-boot/tools/env/env_attr.c @@ -0,0 +1 @@ +#include "../../common/env_attr.c" diff --git a/qemu/roms/u-boot/tools/env/env_flags.c b/qemu/roms/u-boot/tools/env/env_flags.c new file mode 100644 index 000000000..b261cb8e3 --- /dev/null +++ b/qemu/roms/u-boot/tools/env/env_flags.c @@ -0,0 +1 @@ +#include "../../common/env_flags.c" diff --git a/qemu/roms/u-boot/tools/env/fw_env.c b/qemu/roms/u-boot/tools/env/fw_env.c new file mode 100644 index 000000000..30d5b037f --- /dev/null +++ b/qemu/roms/u-boot/tools/env/fw_env.c @@ -0,0 +1,1467 @@ +/* + * (C) Copyright 2000-2010 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2008 + * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <errno.h> +#include <env_flags.h> +#include <fcntl.h> +#include <linux/stringify.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <unistd.h> + +#ifdef MTD_OLD +# include <stdint.h> +# include <linux/mtd/mtd.h> +#else +# define __user /* nothing */ +# include <mtd/mtd-user.h> +#endif + +#include "fw_env.h" + +#include <aes.h> + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) + +#define WHITESPACE(c) ((c == '\t') || (c == ' ')) + +#define min(x, y) ({ \ + typeof(x) _min1 = (x); \ + typeof(y) _min2 = (y); \ + (void) (&_min1 == &_min2); \ + _min1 < _min2 ? _min1 : _min2; }) + +struct envdev_s { + const char *devname; /* Device name */ + ulong devoff; /* Device offset */ + ulong env_size; /* environment size */ + ulong erase_size; /* device erase size */ + ulong env_sectors; /* number of environment sectors */ + uint8_t mtd_type; /* type of the MTD device */ +}; + +static struct envdev_s envdevices[2] = +{ + { + .mtd_type = MTD_ABSENT, + }, { + .mtd_type = MTD_ABSENT, + }, +}; +static int dev_current; + +#define DEVNAME(i) envdevices[(i)].devname +#define DEVOFFSET(i) envdevices[(i)].devoff +#define ENVSIZE(i) envdevices[(i)].env_size +#define DEVESIZE(i) envdevices[(i)].erase_size +#define ENVSECTORS(i) envdevices[(i)].env_sectors +#define DEVTYPE(i) envdevices[(i)].mtd_type + +#define CUR_ENVSIZE ENVSIZE(dev_current) + +#define ENV_SIZE getenvsize() + +struct env_image_single { + uint32_t crc; /* CRC32 over data bytes */ + char data[]; +}; + +struct env_image_redundant { + uint32_t crc; /* CRC32 over data bytes */ + unsigned char flags; /* active or obsolete */ + char data[]; +}; + +enum flag_scheme { + FLAG_NONE, + FLAG_BOOLEAN, + FLAG_INCREMENTAL, +}; + +struct environment { + void *image; + uint32_t *crc; + unsigned char *flags; + char *data; + enum flag_scheme flag_scheme; +}; + +static struct environment environment = { + .flag_scheme = FLAG_NONE, +}; + +/* Is AES encryption used? */ +static int aes_flag; +static uint8_t aes_key[AES_KEY_LENGTH] = { 0 }; +static int env_aes_cbc_crypt(char *data, const int enc); + +static int HaveRedundEnv = 0; + +static unsigned char active_flag = 1; +/* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */ +static unsigned char obsolete_flag = 0; + +#define DEFAULT_ENV_INSTANCE_STATIC +#include <env_default.h> + +static int flash_io (int mode); +static char *envmatch (char * s1, char * s2); +static int parse_config (void); + +#if defined(CONFIG_FILE) +static int get_config (char *); +#endif +static inline ulong getenvsize (void) +{ + ulong rc = CUR_ENVSIZE - sizeof(long); + + if (HaveRedundEnv) + rc -= sizeof (char); + + if (aes_flag) + rc &= ~(AES_KEY_LENGTH - 1); + + return rc; +} + +static char *fw_string_blank(char *s, int noblank) +{ + int i; + int len = strlen(s); + + for (i = 0; i < len; i++, s++) { + if ((noblank && !WHITESPACE(*s)) || + (!noblank && WHITESPACE(*s))) + break; + } + if (i == len) + return NULL; + + return s; +} + +/* + * Search the environment for a variable. + * Return the value, if found, or NULL, if not found. + */ +char *fw_getenv (char *name) +{ + char *env, *nxt; + + for (env = environment.data; *env; env = nxt + 1) { + char *val; + + for (nxt = env; *nxt; ++nxt) { + if (nxt >= &environment.data[ENV_SIZE]) { + fprintf (stderr, "## Error: " + "environment not terminated\n"); + return NULL; + } + } + val = envmatch (name, env); + if (!val) + continue; + return val; + } + return NULL; +} + +/* + * Search the default environment for a variable. + * Return the value, if found, or NULL, if not found. + */ +char *fw_getdefenv(char *name) +{ + char *env, *nxt; + + for (env = default_environment; *env; env = nxt + 1) { + char *val; + + for (nxt = env; *nxt; ++nxt) { + if (nxt >= &default_environment[ENV_SIZE]) { + fprintf(stderr, "## Error: " + "default environment not terminated\n"); + return NULL; + } + } + val = envmatch(name, env); + if (!val) + continue; + return val; + } + return NULL; +} + +static int parse_aes_key(char *key) +{ + char tmp[5] = { '0', 'x', 0, 0, 0 }; + unsigned long ul; + int i; + + if (strnlen(key, 64) != 32) { + fprintf(stderr, + "## Error: '-a' option requires 16-byte AES key\n"); + return -1; + } + + for (i = 0; i < 16; i++) { + tmp[2] = key[0]; + tmp[3] = key[1]; + errno = 0; + ul = strtoul(tmp, NULL, 16); + if (errno) { + fprintf(stderr, + "## Error: '-a' option requires valid AES key\n"); + return -1; + } + aes_key[i] = ul & 0xff; + key += 2; + } + aes_flag = 1; + + return 0; +} + +/* + * Print the current definition of one, or more, or all + * environment variables + */ +int fw_printenv (int argc, char *argv[]) +{ + char *env, *nxt; + int i, n_flag; + int rc = 0; + + if (argc >= 2 && strcmp(argv[1], "-a") == 0) { + if (argc < 3) { + fprintf(stderr, + "## Error: '-a' option requires AES key\n"); + return -1; + } + rc = parse_aes_key(argv[2]); + if (rc) + return rc; + argv += 2; + argc -= 2; + } + + if (fw_env_open()) + return -1; + + if (argc == 1) { /* Print all env variables */ + for (env = environment.data; *env; env = nxt + 1) { + for (nxt = env; *nxt; ++nxt) { + if (nxt >= &environment.data[ENV_SIZE]) { + fprintf (stderr, "## Error: " + "environment not terminated\n"); + return -1; + } + } + + printf ("%s\n", env); + } + return 0; + } + + if (strcmp (argv[1], "-n") == 0) { + n_flag = 1; + ++argv; + --argc; + if (argc != 2) { + fprintf (stderr, "## Error: " + "`-n' option requires exactly one argument\n"); + return -1; + } + } else { + n_flag = 0; + } + + for (i = 1; i < argc; ++i) { /* print single env variables */ + char *name = argv[i]; + char *val = NULL; + + for (env = environment.data; *env; env = nxt + 1) { + + for (nxt = env; *nxt; ++nxt) { + if (nxt >= &environment.data[ENV_SIZE]) { + fprintf (stderr, "## Error: " + "environment not terminated\n"); + return -1; + } + } + val = envmatch (name, env); + if (val) { + if (!n_flag) { + fputs (name, stdout); + putc ('=', stdout); + } + puts (val); + break; + } + } + if (!val) { + fprintf (stderr, "## Error: \"%s\" not defined\n", name); + rc = -1; + } + } + + return rc; +} + +int fw_env_close(void) +{ + int ret; + if (aes_flag) { + ret = env_aes_cbc_crypt(environment.data, 1); + if (ret) { + fprintf(stderr, + "Error: can't encrypt env for flash\n"); + return ret; + } + } + + /* + * Update CRC + */ + *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE); + + /* write environment back to flash */ + if (flash_io(O_RDWR)) { + fprintf(stderr, + "Error: can't write fw_env to flash\n"); + return -1; + } + + return 0; +} + + +/* + * Set/Clear a single variable in the environment. + * This is called in sequence to update the environment + * in RAM without updating the copy in flash after each set + */ +int fw_env_write(char *name, char *value) +{ + int len; + char *env, *nxt; + char *oldval = NULL; + int deleting, creating, overwriting; + + /* + * search if variable with this name already exists + */ + for (nxt = env = environment.data; *env; env = nxt + 1) { + for (nxt = env; *nxt; ++nxt) { + if (nxt >= &environment.data[ENV_SIZE]) { + fprintf(stderr, "## Error: " + "environment not terminated\n"); + errno = EINVAL; + return -1; + } + } + if ((oldval = envmatch (name, env)) != NULL) + break; + } + + deleting = (oldval && !(value && strlen(value))); + creating = (!oldval && (value && strlen(value))); + overwriting = (oldval && (value && strlen(value))); + + /* check for permission */ + if (deleting) { + if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_DELETE)) { + printf("Can't delete \"%s\"\n", name); + errno = EROFS; + return -1; + } + } else if (overwriting) { + if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) { + printf("Can't overwrite \"%s\"\n", name); + errno = EROFS; + return -1; + } else if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) { + const char *defval = fw_getdefenv(name); + + if (defval == NULL) + defval = ""; + if (strcmp(oldval, defval) + != 0) { + printf("Can't overwrite \"%s\"\n", name); + errno = EROFS; + return -1; + } + } + } else if (creating) { + if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_CREATE)) { + printf("Can't create \"%s\"\n", name); + errno = EROFS; + return -1; + } + } else + /* Nothing to do */ + return 0; + + if (deleting || overwriting) { + if (*++nxt == '\0') { + *env = '\0'; + } else { + for (;;) { + *env = *nxt++; + if ((*env == '\0') && (*nxt == '\0')) + break; + ++env; + } + } + *++env = '\0'; + } + + /* Delete only ? */ + if (!value || !strlen(value)) + return 0; + + /* + * Append new definition at the end + */ + for (env = environment.data; *env || *(env + 1); ++env); + if (env > environment.data) + ++env; + /* + * Overflow when: + * "name" + "=" + "val" +"\0\0" > CUR_ENVSIZE - (env-environment) + */ + len = strlen (name) + 2; + /* add '=' for first arg, ' ' for all others */ + len += strlen(value) + 1; + + if (len > (&environment.data[ENV_SIZE] - env)) { + fprintf (stderr, + "Error: environment overflow, \"%s\" deleted\n", + name); + return -1; + } + + while ((*env = *name++) != '\0') + env++; + *env = '='; + while ((*++env = *value++) != '\0') + ; + + /* end is marked with double '\0' */ + *++env = '\0'; + + return 0; +} + +/* + * Deletes or sets environment variables. Returns -1 and sets errno error codes: + * 0 - OK + * EINVAL - need at least 1 argument + * EROFS - certain variables ("ethaddr", "serial#") cannot be + * modified or deleted + * + */ +int fw_setenv(int argc, char *argv[]) +{ + int i, rc; + size_t len; + char *name; + char *value = NULL; + + if (argc < 2) { + errno = EINVAL; + return -1; + } + + if (strcmp(argv[1], "-a") == 0) { + if (argc < 3) { + fprintf(stderr, + "## Error: '-a' option requires AES key\n"); + return -1; + } + rc = parse_aes_key(argv[2]); + if (rc) + return rc; + argv += 2; + argc -= 2; + } + + if (argc < 2) { + errno = EINVAL; + return -1; + } + + if (fw_env_open()) { + fprintf(stderr, "Error: environment not initialized\n"); + return -1; + } + + name = argv[1]; + + if (env_flags_validate_env_set_params(argc, argv) < 0) + return 1; + + len = 0; + for (i = 2; i < argc; ++i) { + char *val = argv[i]; + size_t val_len = strlen(val); + + if (value) + value[len - 1] = ' '; + value = realloc(value, len + val_len + 1); + if (!value) { + fprintf(stderr, + "Cannot malloc %zu bytes: %s\n", + len, strerror(errno)); + return -1; + } + + memcpy(value + len, val, val_len); + len += val_len; + value[len++] = '\0'; + } + + fw_env_write(name, value); + + free(value); + + return fw_env_close(); +} + +/* + * Parse a file and configure the u-boot variables. + * The script file has a very simple format, as follows: + * + * Each line has a couple with name, value: + * <white spaces>variable_name<white spaces>variable_value + * + * Both variable_name and variable_value are interpreted as strings. + * Any character after <white spaces> and before ending \r\n is interpreted + * as variable's value (no comment allowed on these lines !) + * + * Comments are allowed if the first character in the line is # + * + * Returns -1 and sets errno error codes: + * 0 - OK + * -1 - Error + */ +int fw_parse_script(char *fname) +{ + FILE *fp; + char dump[1024]; /* Maximum line length in the file */ + char *name; + char *val; + int lineno = 0; + int len; + int ret = 0; + + if (fw_env_open()) { + fprintf(stderr, "Error: environment not initialized\n"); + return -1; + } + + if (strcmp(fname, "-") == 0) + fp = stdin; + else { + fp = fopen(fname, "r"); + if (fp == NULL) { + fprintf(stderr, "I cannot open %s for reading\n", + fname); + return -1; + } + } + + while (fgets(dump, sizeof(dump), fp)) { + lineno++; + len = strlen(dump); + + /* + * Read a whole line from the file. If the line is too long + * or is not terminated, reports an error and exit. + */ + if (dump[len - 1] != '\n') { + fprintf(stderr, + "Line %d not corrected terminated or too long\n", + lineno); + ret = -1; + break; + } + + /* Drop ending line feed / carriage return */ + while (len > 0 && (dump[len - 1] == '\n' || + dump[len - 1] == '\r')) { + dump[len - 1] = '\0'; + len--; + } + + /* Skip comment or empty lines */ + if ((len == 0) || dump[0] == '#') + continue; + + /* + * Search for variable's name, + * remove leading whitespaces + */ + name = fw_string_blank(dump, 1); + if (!name) + continue; + + /* The first white space is the end of variable name */ + val = fw_string_blank(name, 0); + len = strlen(name); + if (val) { + *val++ = '\0'; + if ((val - name) < len) + val = fw_string_blank(val, 1); + else + val = NULL; + } + +#ifdef DEBUG + fprintf(stderr, "Setting %s : %s\n", + name, val ? val : " removed"); +#endif + + if (env_flags_validate_type(name, val) < 0) { + ret = -1; + break; + } + + /* + * If there is an error setting a variable, + * try to save the environment and returns an error + */ + if (fw_env_write(name, val)) { + fprintf(stderr, + "fw_env_write returns with error : %s\n", + strerror(errno)); + ret = -1; + break; + } + + } + + /* Close file if not stdin */ + if (strcmp(fname, "-") != 0) + fclose(fp); + + ret |= fw_env_close(); + + return ret; + +} + +/* + * Test for bad block on NAND, just returns 0 on NOR, on NAND: + * 0 - block is good + * > 0 - block is bad + * < 0 - failed to test + */ +static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart) +{ + if (mtd_type == MTD_NANDFLASH) { + int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart); + + if (badblock < 0) { + perror ("Cannot read bad block mark"); + return badblock; + } + + if (badblock) { +#ifdef DEBUG + fprintf (stderr, "Bad block at 0x%llx, " + "skipping\n", *blockstart); +#endif + return badblock; + } + } + + return 0; +} + +/* + * Read data from flash at an offset into a provided buffer. On NAND it skips + * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from + * the DEVOFFSET (dev) block. On NOR the loop is only run once. + */ +static int flash_read_buf (int dev, int fd, void *buf, size_t count, + off_t offset, uint8_t mtd_type) +{ + size_t blocklen; /* erase / write length - one block on NAND, + 0 on NOR */ + size_t processed = 0; /* progress counter */ + size_t readlen = count; /* current read length */ + off_t top_of_range; /* end of the last block we may use */ + off_t block_seek; /* offset inside the current block to the start + of the data */ + loff_t blockstart; /* running start of the current block - + MEMGETBADBLOCK needs 64 bits */ + int rc; + + blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev); + + /* Offset inside a block */ + block_seek = offset - blockstart; + + if (mtd_type == MTD_NANDFLASH) { + /* + * NAND: calculate which blocks we are reading. We have + * to read one block at a time to skip bad blocks. + */ + blocklen = DEVESIZE (dev); + + /* + * To calculate the top of the range, we have to use the + * global DEVOFFSET (dev), which can be different from offset + */ + top_of_range = ((DEVOFFSET(dev) / blocklen) + + ENVSECTORS (dev)) * blocklen; + + /* Limit to one block for the first read */ + if (readlen > blocklen - block_seek) + readlen = blocklen - block_seek; + } else { + blocklen = 0; + top_of_range = offset + count; + } + + /* This only runs once on NOR flash */ + while (processed < count) { + rc = flash_bad_block (fd, mtd_type, &blockstart); + if (rc < 0) /* block test failed */ + return -1; + + if (blockstart + block_seek + readlen > top_of_range) { + /* End of range is reached */ + fprintf (stderr, + "Too few good blocks within range\n"); + return -1; + } + + if (rc) { /* block is bad */ + blockstart += blocklen; + continue; + } + + /* + * If a block is bad, we retry in the next block at the same + * offset - see common/env_nand.c::writeenv() + */ + lseek (fd, blockstart + block_seek, SEEK_SET); + + rc = read (fd, buf + processed, readlen); + if (rc != readlen) { + fprintf (stderr, "Read error on %s: %s\n", + DEVNAME (dev), strerror (errno)); + return -1; + } +#ifdef DEBUG + fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n", + rc, blockstart + block_seek, DEVNAME(dev)); +#endif + processed += readlen; + readlen = min (blocklen, count - processed); + block_seek = 0; + blockstart += blocklen; + } + + return processed; +} + +/* + * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of + * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we + * erase and write the whole data at once. + */ +static int flash_write_buf (int dev, int fd, void *buf, size_t count, + off_t offset, uint8_t mtd_type) +{ + void *data; + struct erase_info_user erase; + size_t blocklen; /* length of NAND block / NOR erase sector */ + size_t erase_len; /* whole area that can be erased - may include + bad blocks */ + size_t erasesize; /* erase / write length - one block on NAND, + whole area on NOR */ + size_t processed = 0; /* progress counter */ + size_t write_total; /* total size to actually write - excluding + bad blocks */ + off_t erase_offset; /* offset to the first erase block (aligned) + below offset */ + off_t block_seek; /* offset inside the erase block to the start + of the data */ + off_t top_of_range; /* end of the last block we may use */ + loff_t blockstart; /* running start of the current block - + MEMGETBADBLOCK needs 64 bits */ + int rc; + + /* + * For mtd devices only offset and size of the environment do matter + */ + if (mtd_type == MTD_ABSENT) { + blocklen = count; + top_of_range = offset + count; + erase_len = blocklen; + blockstart = offset; + block_seek = 0; + write_total = blocklen; + } else { + blocklen = DEVESIZE(dev); + + top_of_range = ((DEVOFFSET(dev) / blocklen) + + ENVSECTORS(dev)) * blocklen; + + erase_offset = (offset / blocklen) * blocklen; + + /* Maximum area we may use */ + erase_len = top_of_range - erase_offset; + + blockstart = erase_offset; + /* Offset inside a block */ + block_seek = offset - erase_offset; + + /* + * Data size we actually write: from the start of the block + * to the start of the data, then count bytes of data, and + * to the end of the block + */ + write_total = ((block_seek + count + blocklen - 1) / + blocklen) * blocklen; + } + + /* + * Support data anywhere within erase sectors: read out the complete + * area to be erased, replace the environment image, write the whole + * block back again. + */ + if (write_total > count) { + data = malloc (erase_len); + if (!data) { + fprintf (stderr, + "Cannot malloc %zu bytes: %s\n", + erase_len, strerror (errno)); + return -1; + } + + rc = flash_read_buf (dev, fd, data, write_total, erase_offset, + mtd_type); + if (write_total != rc) + return -1; + +#ifdef DEBUG + fprintf(stderr, "Preserving data "); + if (block_seek != 0) + fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1); + if (block_seek + count != write_total) { + if (block_seek != 0) + fprintf(stderr, " and "); + fprintf(stderr, "0x%lx - 0x%x", + block_seek + count, write_total - 1); + } + fprintf(stderr, "\n"); +#endif + /* Overwrite the old environment */ + memcpy (data + block_seek, buf, count); + } else { + /* + * We get here, iff offset is block-aligned and count is a + * multiple of blocklen - see write_total calculation above + */ + data = buf; + } + + if (mtd_type == MTD_NANDFLASH) { + /* + * NAND: calculate which blocks we are writing. We have + * to write one block at a time to skip bad blocks. + */ + erasesize = blocklen; + } else { + erasesize = erase_len; + } + + erase.length = erasesize; + + /* This only runs once on NOR flash and SPI-dataflash */ + while (processed < write_total) { + rc = flash_bad_block (fd, mtd_type, &blockstart); + if (rc < 0) /* block test failed */ + return rc; + + if (blockstart + erasesize > top_of_range) { + fprintf (stderr, "End of range reached, aborting\n"); + return -1; + } + + if (rc) { /* block is bad */ + blockstart += blocklen; + continue; + } + + if (mtd_type != MTD_ABSENT) { + erase.start = blockstart; + ioctl(fd, MEMUNLOCK, &erase); + /* These do not need an explicit erase cycle */ + if (mtd_type != MTD_DATAFLASH) + if (ioctl(fd, MEMERASE, &erase) != 0) { + fprintf(stderr, + "MTD erase error on %s: %s\n", + DEVNAME(dev), strerror(errno)); + return -1; + } + } + + if (lseek (fd, blockstart, SEEK_SET) == -1) { + fprintf (stderr, + "Seek error on %s: %s\n", + DEVNAME (dev), strerror (errno)); + return -1; + } + +#ifdef DEBUG + fprintf(stderr, "Write 0x%x bytes at 0x%llx\n", erasesize, + blockstart); +#endif + if (write (fd, data + processed, erasesize) != erasesize) { + fprintf (stderr, "Write error on %s: %s\n", + DEVNAME (dev), strerror (errno)); + return -1; + } + + if (mtd_type != MTD_ABSENT) + ioctl(fd, MEMLOCK, &erase); + + processed += erasesize; + block_seek = 0; + blockstart += erasesize; + } + + if (write_total > count) + free (data); + + return processed; +} + +/* + * Set obsolete flag at offset - NOR flash only + */ +static int flash_flag_obsolete (int dev, int fd, off_t offset) +{ + int rc; + struct erase_info_user erase; + + erase.start = DEVOFFSET (dev); + erase.length = DEVESIZE (dev); + /* This relies on the fact, that obsolete_flag == 0 */ + rc = lseek (fd, offset, SEEK_SET); + if (rc < 0) { + fprintf (stderr, "Cannot seek to set the flag on %s \n", + DEVNAME (dev)); + return rc; + } + ioctl (fd, MEMUNLOCK, &erase); + rc = write (fd, &obsolete_flag, sizeof (obsolete_flag)); + ioctl (fd, MEMLOCK, &erase); + if (rc < 0) + perror ("Could not set obsolete flag"); + + return rc; +} + +/* Encrypt or decrypt the environment before writing or reading it. */ +static int env_aes_cbc_crypt(char *payload, const int enc) +{ + uint8_t *data = (uint8_t *)payload; + const int len = getenvsize(); + uint8_t key_exp[AES_EXPAND_KEY_LENGTH]; + uint32_t aes_blocks; + + /* First we expand the key. */ + aes_expand_key(aes_key, key_exp); + + /* Calculate the number of AES blocks to encrypt. */ + aes_blocks = DIV_ROUND_UP(len, AES_KEY_LENGTH); + + if (enc) + aes_cbc_encrypt_blocks(key_exp, data, data, aes_blocks); + else + aes_cbc_decrypt_blocks(key_exp, data, data, aes_blocks); + + return 0; +} + +static int flash_write (int fd_current, int fd_target, int dev_target) +{ + int rc; + + switch (environment.flag_scheme) { + case FLAG_NONE: + break; + case FLAG_INCREMENTAL: + (*environment.flags)++; + break; + case FLAG_BOOLEAN: + *environment.flags = active_flag; + break; + default: + fprintf (stderr, "Unimplemented flash scheme %u \n", + environment.flag_scheme); + return -1; + } + +#ifdef DEBUG + fprintf(stderr, "Writing new environment at 0x%lx on %s\n", + DEVOFFSET (dev_target), DEVNAME (dev_target)); +#endif + + rc = flash_write_buf(dev_target, fd_target, environment.image, + CUR_ENVSIZE, DEVOFFSET(dev_target), + DEVTYPE(dev_target)); + if (rc < 0) + return rc; + + if (environment.flag_scheme == FLAG_BOOLEAN) { + /* Have to set obsolete flag */ + off_t offset = DEVOFFSET (dev_current) + + offsetof (struct env_image_redundant, flags); +#ifdef DEBUG + fprintf(stderr, + "Setting obsolete flag in environment at 0x%lx on %s\n", + DEVOFFSET (dev_current), DEVNAME (dev_current)); +#endif + flash_flag_obsolete (dev_current, fd_current, offset); + } + + return 0; +} + +static int flash_read (int fd) +{ + struct mtd_info_user mtdinfo; + struct stat st; + int rc; + + rc = fstat(fd, &st); + if (rc < 0) { + fprintf(stderr, "Cannot stat the file %s\n", + DEVNAME(dev_current)); + return -1; + } + + if (S_ISCHR(st.st_mode)) { + rc = ioctl(fd, MEMGETINFO, &mtdinfo); + if (rc < 0) { + fprintf(stderr, "Cannot get MTD information for %s\n", + DEVNAME(dev_current)); + return -1; + } + if (mtdinfo.type != MTD_NORFLASH && + mtdinfo.type != MTD_NANDFLASH && + mtdinfo.type != MTD_DATAFLASH && + mtdinfo.type != MTD_UBIVOLUME) { + fprintf (stderr, "Unsupported flash type %u on %s\n", + mtdinfo.type, DEVNAME(dev_current)); + return -1; + } + } else { + memset(&mtdinfo, 0, sizeof(mtdinfo)); + mtdinfo.type = MTD_ABSENT; + } + + DEVTYPE(dev_current) = mtdinfo.type; + + rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE, + DEVOFFSET (dev_current), mtdinfo.type); + if (rc != CUR_ENVSIZE) + return -1; + + return 0; +} + +static int flash_io (int mode) +{ + int fd_current, fd_target, rc, dev_target; + + /* dev_current: fd_current, erase_current */ + fd_current = open (DEVNAME (dev_current), mode); + if (fd_current < 0) { + fprintf (stderr, + "Can't open %s: %s\n", + DEVNAME (dev_current), strerror (errno)); + return -1; + } + + if (mode == O_RDWR) { + if (HaveRedundEnv) { + /* switch to next partition for writing */ + dev_target = !dev_current; + /* dev_target: fd_target, erase_target */ + fd_target = open (DEVNAME (dev_target), mode); + if (fd_target < 0) { + fprintf (stderr, + "Can't open %s: %s\n", + DEVNAME (dev_target), + strerror (errno)); + rc = -1; + goto exit; + } + } else { + dev_target = dev_current; + fd_target = fd_current; + } + + rc = flash_write (fd_current, fd_target, dev_target); + + if (HaveRedundEnv) { + if (close (fd_target)) { + fprintf (stderr, + "I/O error on %s: %s\n", + DEVNAME (dev_target), + strerror (errno)); + rc = -1; + } + } + } else { + rc = flash_read (fd_current); + } + +exit: + if (close (fd_current)) { + fprintf (stderr, + "I/O error on %s: %s\n", + DEVNAME (dev_current), strerror (errno)); + return -1; + } + + return rc; +} + +/* + * s1 is either a simple 'name', or a 'name=value' pair. + * s2 is a 'name=value' pair. + * If the names match, return the value of s2, else NULL. + */ + +static char *envmatch (char * s1, char * s2) +{ + if (s1 == NULL || s2 == NULL) + return NULL; + + while (*s1 == *s2++) + if (*s1++ == '=') + return s2; + if (*s1 == '\0' && *(s2 - 1) == '=') + return s2; + return NULL; +} + +/* + * Prevent confusion if running from erased flash memory + */ +int fw_env_open(void) +{ + int crc0, crc0_ok; + unsigned char flag0; + void *addr0; + + int crc1, crc1_ok; + unsigned char flag1; + void *addr1; + + int ret; + + struct env_image_single *single; + struct env_image_redundant *redundant; + + if (parse_config ()) /* should fill envdevices */ + return -1; + + addr0 = calloc(1, CUR_ENVSIZE); + if (addr0 == NULL) { + fprintf(stderr, + "Not enough memory for environment (%ld bytes)\n", + CUR_ENVSIZE); + return -1; + } + + /* read environment from FLASH to local buffer */ + environment.image = addr0; + + if (HaveRedundEnv) { + redundant = addr0; + environment.crc = &redundant->crc; + environment.flags = &redundant->flags; + environment.data = redundant->data; + } else { + single = addr0; + environment.crc = &single->crc; + environment.flags = NULL; + environment.data = single->data; + } + + dev_current = 0; + if (flash_io (O_RDONLY)) + return -1; + + crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE); + + if (aes_flag) { + ret = env_aes_cbc_crypt(environment.data, 0); + if (ret) + return ret; + } + + crc0_ok = (crc0 == *environment.crc); + if (!HaveRedundEnv) { + if (!crc0_ok) { + fprintf (stderr, + "Warning: Bad CRC, using default environment\n"); + memcpy(environment.data, default_environment, sizeof default_environment); + } + } else { + flag0 = *environment.flags; + + dev_current = 1; + addr1 = calloc(1, CUR_ENVSIZE); + if (addr1 == NULL) { + fprintf(stderr, + "Not enough memory for environment (%ld bytes)\n", + CUR_ENVSIZE); + return -1; + } + redundant = addr1; + + /* + * have to set environment.image for flash_read(), careful - + * other pointers in environment still point inside addr0 + */ + environment.image = addr1; + if (flash_io (O_RDONLY)) + return -1; + + /* Check flag scheme compatibility */ + if (DEVTYPE(dev_current) == MTD_NORFLASH && + DEVTYPE(!dev_current) == MTD_NORFLASH) { + environment.flag_scheme = FLAG_BOOLEAN; + } else if (DEVTYPE(dev_current) == MTD_NANDFLASH && + DEVTYPE(!dev_current) == MTD_NANDFLASH) { + environment.flag_scheme = FLAG_INCREMENTAL; + } else if (DEVTYPE(dev_current) == MTD_DATAFLASH && + DEVTYPE(!dev_current) == MTD_DATAFLASH) { + environment.flag_scheme = FLAG_BOOLEAN; + } else if (DEVTYPE(dev_current) == MTD_UBIVOLUME && + DEVTYPE(!dev_current) == MTD_UBIVOLUME) { + environment.flag_scheme = FLAG_INCREMENTAL; + } else if (DEVTYPE(dev_current) == MTD_ABSENT && + DEVTYPE(!dev_current) == MTD_ABSENT) { + environment.flag_scheme = FLAG_INCREMENTAL; + } else { + fprintf (stderr, "Incompatible flash types!\n"); + return -1; + } + + crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE); + + if (aes_flag) { + ret = env_aes_cbc_crypt(redundant->data, 0); + if (ret) + return ret; + } + + crc1_ok = (crc1 == redundant->crc); + flag1 = redundant->flags; + + if (crc0_ok && !crc1_ok) { + dev_current = 0; + } else if (!crc0_ok && crc1_ok) { + dev_current = 1; + } else if (!crc0_ok && !crc1_ok) { + fprintf (stderr, + "Warning: Bad CRC, using default environment\n"); + memcpy (environment.data, default_environment, + sizeof default_environment); + dev_current = 0; + } else { + switch (environment.flag_scheme) { + case FLAG_BOOLEAN: + if (flag0 == active_flag && + flag1 == obsolete_flag) { + dev_current = 0; + } else if (flag0 == obsolete_flag && + flag1 == active_flag) { + dev_current = 1; + } else if (flag0 == flag1) { + dev_current = 0; + } else if (flag0 == 0xFF) { + dev_current = 0; + } else if (flag1 == 0xFF) { + dev_current = 1; + } else { + dev_current = 0; + } + break; + case FLAG_INCREMENTAL: + if (flag0 == 255 && flag1 == 0) + dev_current = 1; + else if ((flag1 == 255 && flag0 == 0) || + flag0 >= flag1) + dev_current = 0; + else /* flag1 > flag0 */ + dev_current = 1; + break; + default: + fprintf (stderr, "Unknown flag scheme %u \n", + environment.flag_scheme); + return -1; + } + } + + /* + * If we are reading, we don't need the flag and the CRC any + * more, if we are writing, we will re-calculate CRC and update + * flags before writing out + */ + if (dev_current) { + environment.image = addr1; + environment.crc = &redundant->crc; + environment.flags = &redundant->flags; + environment.data = redundant->data; + free (addr0); + } else { + environment.image = addr0; + /* Other pointers are already set */ + free (addr1); + } +#ifdef DEBUG + fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current)); +#endif + } + return 0; +} + + +static int parse_config () +{ + struct stat st; + +#if defined(CONFIG_FILE) + /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ + if (get_config (CONFIG_FILE)) { + fprintf (stderr, + "Cannot parse config file: %s\n", strerror (errno)); + return -1; + } +#else + DEVNAME (0) = DEVICE1_NAME; + DEVOFFSET (0) = DEVICE1_OFFSET; + ENVSIZE (0) = ENV1_SIZE; + /* Default values are: erase-size=env-size */ + DEVESIZE (0) = ENVSIZE (0); + /* #sectors=env-size/erase-size (rounded up) */ + ENVSECTORS (0) = (ENVSIZE(0) + DEVESIZE(0) - 1) / DEVESIZE(0); +#ifdef DEVICE1_ESIZE + DEVESIZE (0) = DEVICE1_ESIZE; +#endif +#ifdef DEVICE1_ENVSECTORS + ENVSECTORS (0) = DEVICE1_ENVSECTORS; +#endif + +#ifdef HAVE_REDUND + DEVNAME (1) = DEVICE2_NAME; + DEVOFFSET (1) = DEVICE2_OFFSET; + ENVSIZE (1) = ENV2_SIZE; + /* Default values are: erase-size=env-size */ + DEVESIZE (1) = ENVSIZE (1); + /* #sectors=env-size/erase-size (rounded up) */ + ENVSECTORS (1) = (ENVSIZE(1) + DEVESIZE(1) - 1) / DEVESIZE(1); +#ifdef DEVICE2_ESIZE + DEVESIZE (1) = DEVICE2_ESIZE; +#endif +#ifdef DEVICE2_ENVSECTORS + ENVSECTORS (1) = DEVICE2_ENVSECTORS; +#endif + HaveRedundEnv = 1; +#endif +#endif + if (stat (DEVNAME (0), &st)) { + fprintf (stderr, + "Cannot access MTD device %s: %s\n", + DEVNAME (0), strerror (errno)); + return -1; + } + + if (HaveRedundEnv && stat (DEVNAME (1), &st)) { + fprintf (stderr, + "Cannot access MTD device %s: %s\n", + DEVNAME (1), strerror (errno)); + return -1; + } + return 0; +} + +#if defined(CONFIG_FILE) +static int get_config (char *fname) +{ + FILE *fp; + int i = 0; + int rc; + char dump[128]; + char *devname; + + fp = fopen (fname, "r"); + if (fp == NULL) + return -1; + + while (i < 2 && fgets (dump, sizeof (dump), fp)) { + /* Skip incomplete conversions and comment strings */ + if (dump[0] == '#') + continue; + + rc = sscanf (dump, "%ms %lx %lx %lx %lx", + &devname, + &DEVOFFSET (i), + &ENVSIZE (i), + &DEVESIZE (i), + &ENVSECTORS (i)); + + if (rc < 3) + continue; + + DEVNAME(i) = devname; + + if (rc < 4) + /* Assume the erase size is the same as the env-size */ + DEVESIZE(i) = ENVSIZE(i); + + if (rc < 5) + /* Assume enough env sectors to cover the environment */ + ENVSECTORS (i) = (ENVSIZE(i) + DEVESIZE(i) - 1) / DEVESIZE(i); + + i++; + } + fclose (fp); + + HaveRedundEnv = i - 1; + if (!i) { /* No valid entries found */ + errno = EINVAL; + return -1; + } else + return 0; +} +#endif diff --git a/qemu/roms/u-boot/tools/env/fw_env.config b/qemu/roms/u-boot/tools/env/fw_env.config new file mode 100644 index 000000000..c9b9f6a16 --- /dev/null +++ b/qemu/roms/u-boot/tools/env/fw_env.config @@ -0,0 +1,22 @@ +# Configuration file for fw_(printenv/setenv) utility. +# Up to two entries are valid, in this case the redundant +# environment sector is assumed present. +# Notice, that the "Number of sectors" is not required on NOR and SPI-dataflash. +# Futhermore, if the Flash sector size is ommitted, this value is assumed to +# be the same as the Environment size, which is valid for NOR and SPI-dataflash + +# NOR example +# MTD device name Device offset Env. size Flash sector size Number of sectors +/dev/mtd1 0x0000 0x4000 0x4000 +/dev/mtd2 0x0000 0x4000 0x4000 + +# MTD SPI-dataflash example +# MTD device name Device offset Env. size Flash sector size Number of sectors +#/dev/mtd5 0x4200 0x4200 +#/dev/mtd6 0x4200 0x4200 + +# NAND example +#/dev/mtd0 0x4000 0x4000 0x20000 2 + +# Block device example +#/dev/mmcblk0 0xc0000 0x20000 diff --git a/qemu/roms/u-boot/tools/env/fw_env.h b/qemu/roms/u-boot/tools/env/fw_env.h new file mode 100644 index 000000000..aff471ba1 --- /dev/null +++ b/qemu/roms/u-boot/tools/env/fw_env.h @@ -0,0 +1,63 @@ +/* + * (C) Copyright 2002-2008 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Pull in the current config to define the default environment */ +#ifndef __ASSEMBLY__ +#define __ASSEMBLY__ /* get only #defines from config.h */ +#include <config.h> +#undef __ASSEMBLY__ +#else +#include <config.h> +#endif + +/* + * To build the utility with the static configuration + * comment out the next line. + * See included "fw_env.config" sample file + * for notes on configuration. + */ +#define CONFIG_FILE "/etc/fw_env.config" + +#ifndef CONFIG_FILE +#define HAVE_REDUND /* For systems with 2 env sectors */ +#define DEVICE1_NAME "/dev/mtd1" +#define DEVICE2_NAME "/dev/mtd2" +#define DEVICE1_OFFSET 0x0000 +#define ENV1_SIZE 0x4000 +#define DEVICE1_ESIZE 0x4000 +#define DEVICE1_ENVSECTORS 2 +#define DEVICE2_OFFSET 0x0000 +#define ENV2_SIZE 0x4000 +#define DEVICE2_ESIZE 0x4000 +#define DEVICE2_ENVSECTORS 2 +#endif + +#ifndef CONFIG_BAUDRATE +#define CONFIG_BAUDRATE 115200 +#endif + +#ifndef CONFIG_BOOTDELAY +#define CONFIG_BOOTDELAY 5 /* autoboot after 5 seconds */ +#endif + +#ifndef CONFIG_BOOTCOMMAND +#define CONFIG_BOOTCOMMAND \ + "bootp; " \ + "setenv bootargs root=/dev/nfs nfsroot=${serverip}:${rootpath} " \ + "ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; " \ + "bootm" +#endif + +extern int fw_printenv(int argc, char *argv[]); +extern char *fw_getenv (char *name); +extern int fw_setenv (int argc, char *argv[]); +extern int fw_parse_script(char *fname); +extern int fw_env_open(void); +extern int fw_env_write(char *name, char *value); +extern int fw_env_close(void); + +extern unsigned long crc32 (unsigned long, const unsigned char *, unsigned); diff --git a/qemu/roms/u-boot/tools/env/fw_env_main.c b/qemu/roms/u-boot/tools/env/fw_env_main.c new file mode 100644 index 000000000..ce50d58b6 --- /dev/null +++ b/qemu/roms/u-boot/tools/env/fw_env_main.c @@ -0,0 +1,147 @@ +/* + * (C) Copyright 2000-2008 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Command line user interface to firmware (=U-Boot) environment. + * + * Implements: + * fw_printenv [ -a key ] [[ -n name ] | [ name ... ]] + * - prints the value of a single environment variable + * "name", the ``name=value'' pairs of one or more + * environment variables "name", or the whole + * environment if no names are specified. + * fw_setenv [ -a key ] name [ value ... ] + * - If a name without any values is given, the variable + * with this name is deleted from the environment; + * otherwise, all "value" arguments are concatenated, + * separated by single blank characters, and the + * resulting string is assigned to the environment + * variable "name" + * + * If '-a key' is specified, the env block is encrypted with AES 128 CBC. + * The 'key' argument is in the format of 32 hexadecimal numbers (16 bytes + * of AES key), eg. '-a aabbccddeeff00112233445566778899'. + */ + +#include <fcntl.h> +#include <getopt.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/file.h> +#include <unistd.h> +#include "fw_env.h" + +#define CMD_PRINTENV "fw_printenv" +#define CMD_SETENV "fw_setenv" + +static struct option long_options[] = { + {"script", required_argument, NULL, 's'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} +}; + +void usage(void) +{ + + fprintf(stderr, "fw_printenv/fw_setenv, " + "a command line interface to U-Boot environment\n\n" + "usage:\tfw_printenv [-a key] [-n] [variable name]\n" + "\tfw_setenv [-a key] [variable name] [variable value]\n" + "\tfw_setenv -s [ file ]\n" + "\tfw_setenv -s - < [ file ]\n\n" + "The file passed as argument contains only pairs " + "name / value\n" + "Example:\n" + "# Any line starting with # is treated as comment\n" + "\n" + "\t netdev eth0\n" + "\t kernel_addr 400000\n" + "\t var1\n" + "\t var2 The quick brown fox jumps over the " + "lazy dog\n" + "\n" + "A variable without value will be dropped. It is possible\n" + "to put any number of spaces between the fields, but any\n" + "space inside the value is treated as part of the value " + "itself.\n\n" + ); +} + +int main(int argc, char *argv[]) +{ + char *p; + char *cmdname = *argv; + char *script_file = NULL; + int c; + const char *lockname = "/var/lock/" CMD_PRINTENV ".lock"; + int lockfd = -1; + int retval = EXIT_SUCCESS; + + lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (-1 == lockfd) { + fprintf(stderr, "Error opening lock file %s\n", lockname); + return EXIT_FAILURE; + } + + if (-1 == flock(lockfd, LOCK_EX)) { + fprintf(stderr, "Error locking file %s\n", lockname); + close(lockfd); + return EXIT_FAILURE; + } + + if ((p = strrchr (cmdname, '/')) != NULL) { + cmdname = p + 1; + } + + while ((c = getopt_long (argc, argv, "a:ns:h", + long_options, NULL)) != EOF) { + switch (c) { + case 'a': + /* AES key, handled later */ + break; + case 'n': + /* handled in fw_printenv */ + break; + case 's': + script_file = optarg; + break; + case 'h': + usage(); + goto exit; + default: /* '?' */ + fprintf(stderr, "Try `%s --help' for more information." + "\n", cmdname); + retval = EXIT_FAILURE; + goto exit; + } + } + + if (strcmp(cmdname, CMD_PRINTENV) == 0) { + if (fw_printenv(argc, argv) != 0) + retval = EXIT_FAILURE; + } else if (strcmp(cmdname, CMD_SETENV) == 0) { + if (!script_file) { + if (fw_setenv(argc, argv) != 0) + retval = EXIT_FAILURE; + } else { + if (fw_parse_script(script_file) != 0) + retval = EXIT_FAILURE; + } + } else { + fprintf(stderr, + "Identity crisis - may be called as `" CMD_PRINTENV + "' or as `" CMD_SETENV "' but not as `%s'\n", + cmdname); + retval = EXIT_FAILURE; + } + +exit: + flock(lockfd, LOCK_UN); + close(lockfd); + return retval; +} diff --git a/qemu/roms/u-boot/tools/env/linux_string.c b/qemu/roms/u-boot/tools/env/linux_string.c new file mode 100644 index 000000000..6c01addad --- /dev/null +++ b/qemu/roms/u-boot/tools/env/linux_string.c @@ -0,0 +1 @@ +#include "../../lib/linux_string.c" diff --git a/qemu/roms/u-boot/tools/env_embedded.c b/qemu/roms/u-boot/tools/env_embedded.c new file mode 100644 index 000000000..59a635719 --- /dev/null +++ b/qemu/roms/u-boot/tools/env_embedded.c @@ -0,0 +1 @@ +#include "../common/env_embedded.c" diff --git a/qemu/roms/u-boot/tools/envcrc.c b/qemu/roms/u-boot/tools/envcrc.c new file mode 100644 index 000000000..a9d9b48c7 --- /dev/null +++ b/qemu/roms/u-boot/tools/envcrc.c @@ -0,0 +1,129 @@ +/* + * (C) Copyright 2001 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <errno.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifndef __ASSEMBLY__ +#define __ASSEMBLY__ /* Dirty trick to get only #defines */ +#endif +#define __ASM_STUB_PROCESSOR_H__ /* don't include asm/processor. */ +#include <config.h> +#undef __ASSEMBLY__ + +#if defined(CONFIG_ENV_IS_IN_FLASH) +# ifndef CONFIG_ENV_ADDR +# define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET) +# endif +# ifndef CONFIG_ENV_OFFSET +# define CONFIG_ENV_OFFSET (CONFIG_ENV_ADDR - CONFIG_SYS_FLASH_BASE) +# endif +# if !defined(CONFIG_ENV_ADDR_REDUND) && defined(CONFIG_ENV_OFFSET_REDUND) +# define CONFIG_ENV_ADDR_REDUND (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET_REDUND) +# endif +# ifndef CONFIG_ENV_SIZE +# define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE +# endif +# if defined(CONFIG_ENV_ADDR_REDUND) && !defined(CONFIG_ENV_SIZE_REDUND) +# define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE +# endif +# if (CONFIG_ENV_ADDR >= CONFIG_SYS_MONITOR_BASE) && \ + ((CONFIG_ENV_ADDR + CONFIG_ENV_SIZE) <= (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN)) +# define ENV_IS_EMBEDDED +# endif +# if defined(CONFIG_ENV_ADDR_REDUND) || defined(CONFIG_ENV_OFFSET_REDUND) +# define CONFIG_SYS_REDUNDAND_ENVIRONMENT +# endif +#endif /* CONFIG_ENV_IS_IN_FLASH */ + +#if defined(ENV_IS_EMBEDDED) && !defined(CONFIG_BUILD_ENVCRC) +# define CONFIG_BUILD_ENVCRC +#endif + +#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT +# define ENV_HEADER_SIZE (sizeof(uint32_t) + 1) +#else +# define ENV_HEADER_SIZE (sizeof(uint32_t)) +#endif + +#define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE) + + +#ifdef CONFIG_BUILD_ENVCRC +# include <environment.h> +extern unsigned int env_size; +extern env_t environment; +#endif /* CONFIG_BUILD_ENVCRC */ + +extern uint32_t crc32 (uint32_t, const unsigned char *, unsigned int); + +int main (int argc, char **argv) +{ +#ifdef CONFIG_BUILD_ENVCRC + unsigned char pad = 0x00; + uint32_t crc; + unsigned char *envptr = (unsigned char *)&environment, + *dataptr = envptr + ENV_HEADER_SIZE; + unsigned int datasize = ENV_SIZE; + unsigned int eoe; + + if (argv[1] && !strncmp(argv[1], "--binary", 8)) { + int ipad = 0xff; + if (argv[1][8] == '=') + sscanf(argv[1] + 9, "%i", &ipad); + pad = ipad; + } + + if (pad) { + /* find the end of env */ + for (eoe = 0; eoe < datasize - 1; ++eoe) + if (!dataptr[eoe] && !dataptr[eoe+1]) { + eoe += 2; + break; + } + if (eoe < datasize - 1) + memset(dataptr + eoe, pad, datasize - eoe); + } + + crc = crc32 (0, dataptr, datasize); + + /* Check if verbose mode is activated passing a parameter to the program */ + if (argc > 1) { + if (!strncmp(argv[1], "--binary", 8)) { + int le = (argc > 2 ? !strcmp(argv[2], "le") : 1); + size_t i, start, end, step; + if (le) { + start = 0; + end = ENV_HEADER_SIZE; + step = 1; + } else { + start = ENV_HEADER_SIZE - 1; + end = -1; + step = -1; + } + for (i = start; i != end; i += step) + printf("%c", (crc & (0xFF << (i * 8))) >> (i * 8)); + if (fwrite(dataptr, 1, datasize, stdout) != datasize) + fprintf(stderr, "fwrite() failed: %s\n", strerror(errno)); + } else { + printf("CRC32 from offset %08X to %08X of environment = %08X\n", + (unsigned int) (dataptr - envptr), + (unsigned int) (dataptr - envptr) + datasize, + crc); + } + } else { + printf ("0x%08X\n", crc); + } +#else + printf ("0\n"); +#endif + return EXIT_SUCCESS; +} diff --git a/qemu/roms/u-boot/tools/fdt.c b/qemu/roms/u-boot/tools/fdt.c new file mode 100644 index 000000000..1eafc56d7 --- /dev/null +++ b/qemu/roms/u-boot/tools/fdt.c @@ -0,0 +1 @@ +#include "../lib/libfdt/fdt.c" diff --git a/qemu/roms/u-boot/tools/fdt_host.h b/qemu/roms/u-boot/tools/fdt_host.h new file mode 100644 index 000000000..134d96571 --- /dev/null +++ b/qemu/roms/u-boot/tools/fdt_host.h @@ -0,0 +1,16 @@ +/* + * (C) Copyright 2008 Semihalf + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FDT_HOST_H__ +#define __FDT_HOST_H__ + +/* Make sure to include u-boot version of libfdt include files */ +#include "../include/libfdt.h" +#include "../include/fdt_support.h" + +int fit_check_sign(const void *working_fdt, const void *key); + +#endif /* __FDT_HOST_H__ */ diff --git a/qemu/roms/u-boot/tools/fdt_ro.c b/qemu/roms/u-boot/tools/fdt_ro.c new file mode 100644 index 000000000..9005fe3ca --- /dev/null +++ b/qemu/roms/u-boot/tools/fdt_ro.c @@ -0,0 +1 @@ +#include "../lib/libfdt/fdt_ro.c" diff --git a/qemu/roms/u-boot/tools/fdt_rw.c b/qemu/roms/u-boot/tools/fdt_rw.c new file mode 100644 index 000000000..adc3fdfbe --- /dev/null +++ b/qemu/roms/u-boot/tools/fdt_rw.c @@ -0,0 +1 @@ +#include "../lib/libfdt/fdt_rw.c" diff --git a/qemu/roms/u-boot/tools/fdt_strerror.c b/qemu/roms/u-boot/tools/fdt_strerror.c new file mode 100644 index 000000000..d0b58220a --- /dev/null +++ b/qemu/roms/u-boot/tools/fdt_strerror.c @@ -0,0 +1 @@ +#include "../lib/libfdt/fdt_strerror.c" diff --git a/qemu/roms/u-boot/tools/fdt_wip.c b/qemu/roms/u-boot/tools/fdt_wip.c new file mode 100644 index 000000000..7810f0707 --- /dev/null +++ b/qemu/roms/u-boot/tools/fdt_wip.c @@ -0,0 +1 @@ +#include "../lib/libfdt/fdt_wip.c" diff --git a/qemu/roms/u-boot/tools/fdtdec.c b/qemu/roms/u-boot/tools/fdtdec.c new file mode 100644 index 000000000..f1c22569c --- /dev/null +++ b/qemu/roms/u-boot/tools/fdtdec.c @@ -0,0 +1 @@ +#include "../lib/fdtdec.c" diff --git a/qemu/roms/u-boot/tools/fit_check_sign.c b/qemu/roms/u-boot/tools/fit_check_sign.c new file mode 100644 index 000000000..d6d934009 --- /dev/null +++ b/qemu/roms/u-boot/tools/fit_check_sign.c @@ -0,0 +1,85 @@ +/* + * (C) Copyright 2014 + * DENX Software Engineering + * Heiko Schocher <hs@denx.de> + * + * Based on: + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2004 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * + * Updated-by: Prafulla Wadaskar <prafulla@marvell.com> + * FIT image specific code abstracted from mkimage.c + * some functions added to address abstraction + * + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "mkimage.h" +#include "fit_common.h" +#include <image.h> +#include <u-boot/crc.h> + +void usage(char *cmdname) +{ + fprintf(stderr, "Usage: %s -f fit file -k key file\n" + " -f ==> set fit file which should be checked'\n" + " -k ==> set key file which contains the key'\n", + cmdname); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + int ffd = -1; + int kfd = -1; + struct stat fsbuf; + struct stat ksbuf; + void *fit_blob; + char *fdtfile = NULL; + char *keyfile = NULL; + char cmdname[50]; + int ret; + void *key_blob; + int c; + + strcpy(cmdname, *argv); + while ((c = getopt(argc, argv, "f:k:")) != -1) + switch (c) { + case 'f': + fdtfile = optarg; + break; + case 'k': + keyfile = optarg; + break; + default: + usage(cmdname); + break; + } + + ffd = mmap_fdt(cmdname, fdtfile, &fit_blob, &fsbuf, 0); + if (ffd < 0) + return EXIT_FAILURE; + kfd = mmap_fdt(cmdname, keyfile, &key_blob, &ksbuf, 0); + if (ffd < 0) + return EXIT_FAILURE; + + image_set_host_blob(key_blob); + ret = fit_check_sign(fit_blob, key_blob); + + if (ret) + ret = EXIT_SUCCESS; + else + ret = EXIT_FAILURE; + + (void) munmap((void *)fit_blob, fsbuf.st_size); + (void) munmap((void *)key_blob, ksbuf.st_size); + + close(ffd); + close(kfd); + exit(ret); +} diff --git a/qemu/roms/u-boot/tools/fit_common.c b/qemu/roms/u-boot/tools/fit_common.c new file mode 100644 index 000000000..ee1767bd0 --- /dev/null +++ b/qemu/roms/u-boot/tools/fit_common.c @@ -0,0 +1,86 @@ +/* + * (C) Copyright 2014 + * DENX Software Engineering + * Heiko Schocher <hs@denx.de> + * + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2004 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * + * Updated-by: Prafulla Wadaskar <prafulla@marvell.com> + * FIT image specific code abstracted from mkimage.c + * some functions added to address abstraction + * + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include "mkimage.h" +#include "fit_common.h" +#include <image.h> +#include <u-boot/crc.h> + +int fit_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + return fdt_check_header(ptr); +} + +int fit_check_image_types(uint8_t type) +{ + if (type == IH_TYPE_FLATDT) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +} + +int mmap_fdt(char *cmdname, const char *fname, void **blobp, + struct stat *sbuf, int useunlink) +{ + void *ptr; + int fd; + + /* Load FIT blob into memory (we need to write hashes/signatures) */ + fd = open(fname, O_RDWR | O_BINARY); + + if (fd < 0) { + fprintf(stderr, "%s: Can't open %s: %s\n", + cmdname, fname, strerror(errno)); + if (useunlink) + unlink(fname); + return -1; + } + + if (fstat(fd, sbuf) < 0) { + fprintf(stderr, "%s: Can't stat %s: %s\n", + cmdname, fname, strerror(errno)); + if (useunlink) + unlink(fname); + return -1; + } + + errno = 0; + ptr = mmap(0, sbuf->st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if ((ptr == MAP_FAILED) || (errno != 0)) { + fprintf(stderr, "%s: Can't read %s: %s\n", + cmdname, fname, strerror(errno)); + if (useunlink) + unlink(fname); + return -1; + } + + /* check if ptr has a valid blob */ + if (fdt_check_header(ptr)) { + fprintf(stderr, "%s: Invalid FIT blob\n", cmdname); + if (useunlink) + unlink(fname); + return -1; + } + + *blobp = ptr; + return fd; +} diff --git a/qemu/roms/u-boot/tools/fit_common.h b/qemu/roms/u-boot/tools/fit_common.h new file mode 100644 index 000000000..adf440480 --- /dev/null +++ b/qemu/roms/u-boot/tools/fit_common.h @@ -0,0 +1,22 @@ +/* + * (C) Copyright 2014 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _FIT_COMMON_H_ +#define _FIT_COMMON_H_ + +#include "imagetool.h" +#include "mkimage.h" +#include <image.h> + +int fit_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params); + +int fit_check_image_types(uint8_t type); + +int mmap_fdt(char *cmdname, const char *fname, void **blobp, + struct stat *sbuf, int useunlink); + +#endif /* _FIT_COMMON_H_ */ diff --git a/qemu/roms/u-boot/tools/fit_image.c b/qemu/roms/u-boot/tools/fit_image.c new file mode 100644 index 000000000..eeee484cd --- /dev/null +++ b/qemu/roms/u-boot/tools/fit_image.c @@ -0,0 +1,156 @@ +/* + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2004 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * + * Updated-by: Prafulla Wadaskar <prafulla@marvell.com> + * FIT image specific code abstracted from mkimage.c + * some functions added to address abstraction + * + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include "fit_common.h" +#include "mkimage.h" +#include <image.h> +#include <u-boot/crc.h> + +static image_header_t header; + +/** + * fit_handle_file - main FIT file processing function + * + * fit_handle_file() runs dtc to convert .its to .itb, includes + * binary data, updates timestamp property and calculates hashes. + * + * datafile - .its file + * imagefile - .itb file + * + * returns: + * only on success, otherwise calls exit (EXIT_FAILURE); + */ +static int fit_handle_file(struct image_tool_params *params) +{ + char tmpfile[MKIMAGE_MAX_TMPFILE_LEN]; + char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; + int tfd, destfd = 0; + void *dest_blob = NULL; + struct stat sbuf; + void *ptr; + off_t destfd_size = 0; + + /* Flattened Image Tree (FIT) format handling */ + debug ("FIT format handling\n"); + + /* call dtc to include binary properties into the tmp file */ + if (strlen (params->imagefile) + + strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) { + fprintf (stderr, "%s: Image file name (%s) too long, " + "can't create tmpfile", + params->imagefile, params->cmdname); + return (EXIT_FAILURE); + } + sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX); + + /* We either compile the source file, or use the existing FIT image */ + if (params->datafile) { + /* dtc -I dts -O dtb -p 500 datafile > tmpfile */ + snprintf(cmd, sizeof(cmd), "%s %s %s > %s", + MKIMAGE_DTC, params->dtc, params->datafile, tmpfile); + debug("Trying to execute \"%s\"\n", cmd); + } else { + snprintf(cmd, sizeof(cmd), "cp %s %s", + params->imagefile, tmpfile); + } + if (system (cmd) == -1) { + fprintf (stderr, "%s: system(%s) failed: %s\n", + params->cmdname, cmd, strerror(errno)); + goto err_system; + } + + if (params->keydest) { + destfd = mmap_fdt(params->cmdname, params->keydest, + &dest_blob, &sbuf, 1); + if (destfd < 0) + goto err_keydest; + destfd_size = sbuf.st_size; + } + + tfd = mmap_fdt(params->cmdname, tmpfile, &ptr, &sbuf, 1); + if (tfd < 0) + goto err_mmap; + + /* set hashes for images in the blob */ + if (fit_add_verification_data(params->keydir, + dest_blob, ptr, params->comment, + params->require_keys)) { + fprintf(stderr, "%s Can't add hashes to FIT blob\n", + params->cmdname); + goto err_add_hashes; + } + + /* for first image creation, add a timestamp at offset 0 i.e., root */ + if (params->datafile && fit_set_timestamp(ptr, 0, sbuf.st_mtime)) { + fprintf (stderr, "%s: Can't add image timestamp\n", + params->cmdname); + goto err_add_timestamp; + } + debug ("Added timestamp successfully\n"); + + munmap ((void *)ptr, sbuf.st_size); + close (tfd); + if (dest_blob) { + munmap(dest_blob, destfd_size); + close(destfd); + } + + if (rename (tmpfile, params->imagefile) == -1) { + fprintf (stderr, "%s: Can't rename %s to %s: %s\n", + params->cmdname, tmpfile, params->imagefile, + strerror (errno)); + unlink (tmpfile); + unlink (params->imagefile); + return (EXIT_FAILURE); + } + return (EXIT_SUCCESS); + +err_add_timestamp: +err_add_hashes: + munmap(ptr, sbuf.st_size); +err_mmap: + if (dest_blob) + munmap(dest_blob, destfd_size); +err_keydest: +err_system: + unlink(tmpfile); + return -1; +} + +static int fit_check_params(struct image_tool_params *params) +{ + return ((params->dflag && (params->fflag || params->lflag)) || + (params->fflag && (params->dflag || params->lflag)) || + (params->lflag && (params->dflag || params->fflag))); +} + +static struct image_type_params fitimage_params = { + .name = "FIT Image support", + .header_size = sizeof(image_header_t), + .hdr = (void*)&header, + .verify_header = fit_verify_header, + .print_header = fit_print_contents, + .check_image_type = fit_check_image_types, + .fflag_handle = fit_handle_file, + .set_header = NULL, /* FIT images use DTB header */ + .check_params = fit_check_params, +}; + +void init_fit_image_type (void) +{ + register_image_type(&fitimage_params); +} diff --git a/qemu/roms/u-boot/tools/fit_info.c b/qemu/roms/u-boot/tools/fit_info.c new file mode 100644 index 000000000..50f3c8edf --- /dev/null +++ b/qemu/roms/u-boot/tools/fit_info.c @@ -0,0 +1,96 @@ +/* + * (C) Copyright 2014 + * DENX Software Engineering + * Heiko Schocher <hs@denx.de> + * + * fit_info: print the offset and the len of a property from + * node in a fit file. + * + * Based on: + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2004 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * + * Updated-by: Prafulla Wadaskar <prafulla@marvell.com> + * FIT image specific code abstracted from mkimage.c + * some functions added to address abstraction + * + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "mkimage.h" +#include "fit_common.h" +#include <image.h> +#include <u-boot/crc.h> + +void usage(char *cmdname) +{ + fprintf(stderr, "Usage: %s -f fit file -n node -p property\n" + " -f ==> set fit file which is used'\n" + " -n ==> set node name'\n" + " -p ==> set property name'\n", + cmdname); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + int ffd = -1; + struct stat fsbuf; + void *fit_blob; + int len; + int nodeoffset; /* node offset from libfdt */ + const void *nodep; /* property node pointer */ + char *fdtfile = NULL; + char *nodename = NULL; + char *propertyname = NULL; + char cmdname[50]; + int c; + + strcpy(cmdname, *argv); + while ((c = getopt(argc, argv, "f:n:p:")) != -1) + switch (c) { + case 'f': + fdtfile = optarg; + break; + case 'n': + nodename = optarg; + break; + case 'p': + propertyname = optarg; + break; + default: + usage(cmdname); + break; + } + + ffd = mmap_fdt(cmdname, fdtfile, &fit_blob, &fsbuf, 0); + + if (ffd < 0) { + printf("Could not open %s\n", fdtfile); + exit(EXIT_FAILURE); + } + + nodeoffset = fdt_path_offset(fit_blob, nodename); + if (nodeoffset < 0) { + printf("%s not found.", nodename); + exit(EXIT_FAILURE); + } + nodep = fdt_getprop(fit_blob, nodeoffset, propertyname, &len); + if (len == 0) { + printf("len == 0 %s\n", propertyname); + exit(EXIT_FAILURE); + } + + printf("NAME: %s\n", fit_get_name(fit_blob, nodeoffset, NULL)); + printf("LEN: %d\n", len); + printf("OFF: %d\n", (int)(nodep - fit_blob)); + (void) munmap((void *)fit_blob, fsbuf.st_size); + + close(ffd); + exit(EXIT_SUCCESS); +} diff --git a/qemu/roms/u-boot/tools/gdb/Makefile b/qemu/roms/u-boot/tools/gdb/Makefile new file mode 100644 index 000000000..451332031 --- /dev/null +++ b/qemu/roms/u-boot/tools/gdb/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2000 +# Murray Jensen <Murray.Jensen@csiro.au> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +ifneq ($(HOSTOS),cygwin) + +# Location of a usable BFD library, where we define "usable" as +# "built for ${HOST}, supports ${TARGET}". Sensible values are +# - When cross-compiling: the root of the cross-environment +# - Linux/ppc (native): /usr +# - NetBSD/ppc (native): you lose ... (must extract these from the +# binutils build directory, plus the native and U-Boot include +# files don't like each other) + +ifeq ($(HOSTOS),darwin) +BFD_ROOT_DIR = /usr/local/tools +else +ifeq ($(HOSTARCH),$(ARCH)) +# native +BFD_ROOT_DIR = /usr +else +#BFD_ROOT_DIR = /LinuxPPC/CDK # Linux/i386 +#BFD_ROOT_DIR = /usr/pkg/cross # NetBSD/i386 +BFD_ROOT_DIR = /opt/powerpc +endif +endif + +# +# Use native tools and options +# +HOST_EXTRACFLAGS := -I$(BFD_ROOT_DIR)/include -pedantic + +hostprogs-y := gdbsend gdbcont + +gdbsend-objs := gdbsend.o error.o remote.o serial.o +gdbcont-objs := gdbcont.o error.o remote.o serial.o + +always := $(hostprogs-y) + +endif # cygwin diff --git a/qemu/roms/u-boot/tools/gdb/error.c b/qemu/roms/u-boot/tools/gdb/error.c new file mode 100644 index 000000000..4c32ce55f --- /dev/null +++ b/qemu/roms/u-boot/tools/gdb/error.c @@ -0,0 +1,65 @@ +/* + * (C) Copyright 2000 + * Murray Jensen <Murray.Jensen@csiro.au> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include "error.h" + +char *pname; + +void +Warning(char *fmt, ...) +{ + va_list args; + + fprintf(stderr, "%s: WARNING: ", pname); + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + fprintf(stderr, "\n"); +} + +void +Error(char *fmt, ...) +{ + va_list args; + + fprintf(stderr, "%s: ERROR: ", pname); + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + fprintf(stderr, "\n"); + + exit(1); +} + +void +Perror(char *fmt, ...) +{ + va_list args; + int e = errno; + char *p; + + fprintf(stderr, "%s: ERROR: ", pname); + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + if ((p = strerror(e)) == NULL || *p == '\0') + fprintf(stderr, ": Unknown Error (%d)\n", e); + else + fprintf(stderr, ": %s\n", p); + + exit(1); +} diff --git a/qemu/roms/u-boot/tools/gdb/error.h b/qemu/roms/u-boot/tools/gdb/error.h new file mode 100644 index 000000000..fdadaacc6 --- /dev/null +++ b/qemu/roms/u-boot/tools/gdb/error.h @@ -0,0 +1,14 @@ +/* + * (C) Copyright 2000 + * Murray Jensen <Murray.Jensen@csiro.au> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <stdarg.h> + +extern char *pname; + +extern void Warning(char *, ...); +extern void Error(char *, ...); +extern void Perror(char *, ...); diff --git a/qemu/roms/u-boot/tools/gdb/gdbcont.c b/qemu/roms/u-boot/tools/gdb/gdbcont.c new file mode 100644 index 000000000..761bdb0aa --- /dev/null +++ b/qemu/roms/u-boot/tools/gdb/gdbcont.c @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2000 + * Murray Jensen <Murray.Jensen@csiro.au> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "serial.h" +#include "error.h" +#include "remote.h" + +char *serialdev = "/dev/term/b"; +speed_t speed = B230400; +int verbose = 0; + +int +main(int ac, char **av) +{ + int c, sfd; + + if ((pname = strrchr(av[0], '/')) == NULL) + pname = av[0]; + else + pname++; + + while ((c = getopt(ac, av, "b:p:v")) != EOF) + switch (c) { + + case 'b': + if ((speed = cvtspeed(optarg)) == B0) + Error("can't decode baud rate specified in -b option"); + break; + + case 'p': + serialdev = optarg; + break; + + case 'v': + verbose = 1; + break; + + default: + usage: + fprintf(stderr, "Usage: %s [-b bps] [-p dev] [-v]\n", pname); + exit(1); + } + if (optind != ac) + goto usage; + + if (verbose) + fprintf(stderr, "Opening serial port and sending continue...\n"); + + if ((sfd = serialopen(serialdev, speed)) < 0) + Perror("open of serial device '%s' failed", serialdev); + + remote_desc = sfd; + remote_reset(); + remote_continue(); + + if (serialclose(sfd) < 0) + Perror("close of serial device '%s' failed", serialdev); + + if (verbose) + fprintf(stderr, "Done.\n"); + + return (0); +} diff --git a/qemu/roms/u-boot/tools/gdb/gdbsend.c b/qemu/roms/u-boot/tools/gdb/gdbsend.c new file mode 100644 index 000000000..bb28c7214 --- /dev/null +++ b/qemu/roms/u-boot/tools/gdb/gdbsend.c @@ -0,0 +1,121 @@ +/* + * (C) Copyright 2000 + * Murray Jensen <Murray.Jensen@csiro.au> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "serial.h" +#include "error.h" +#include "remote.h" + +char *serialdev = "/dev/term/b"; +speed_t speed = B230400; +int verbose = 0, docont = 0; +unsigned long addr = 0x10000UL; + +int +main(int ac, char **av) +{ + int c, sfd, ifd; + char *ifn, *image; + struct stat ist; + + if ((pname = strrchr(av[0], '/')) == NULL) + pname = av[0]; + else + pname++; + + while ((c = getopt(ac, av, "a:b:cp:v")) != EOF) + switch (c) { + + case 'a': { + char *ep; + + addr = strtol(optarg, &ep, 0); + if (ep == optarg || *ep != '\0') + Error("can't decode address specified in -a option"); + break; + } + + case 'b': + if ((speed = cvtspeed(optarg)) == B0) + Error("can't decode baud rate specified in -b option"); + break; + + case 'c': + docont = 1; + break; + + case 'p': + serialdev = optarg; + break; + + case 'v': + verbose = 1; + break; + + default: + usage: + fprintf(stderr, + "Usage: %s [-a addr] [-b bps] [-c] [-p dev] [-v] imagefile\n", + pname); + exit(1); + } + + if (optind != ac - 1) + goto usage; + ifn = av[optind++]; + + if (verbose) + fprintf(stderr, "Opening file and reading image...\n"); + + if ((ifd = open(ifn, O_RDONLY)) < 0) + Perror("can't open kernel image file '%s'", ifn); + + if (fstat(ifd, &ist) < 0) + Perror("fstat '%s' failed", ifn); + + if ((image = (char *)malloc(ist.st_size)) == NULL) + Perror("can't allocate %ld bytes for image", ist.st_size); + + if ((c = read(ifd, image, ist.st_size)) < 0) + Perror("read of %d bytes from '%s' failed", ist.st_size, ifn); + + if (c != ist.st_size) + Error("read of %ld bytes from '%s' failed (%d)", ist.st_size, ifn, c); + + if (close(ifd) < 0) + Perror("close of '%s' failed", ifn); + + if (verbose) + fprintf(stderr, "Opening serial port and sending image...\n"); + + if ((sfd = serialopen(serialdev, speed)) < 0) + Perror("open of serial device '%s' failed", serialdev); + + remote_desc = sfd; + remote_reset(); + remote_write_bytes(addr, image, ist.st_size); + + if (docont) { + if (verbose) + fprintf(stderr, "[continue]"); + remote_continue(); + } + + if (serialclose(sfd) < 0) + Perror("close of serial device '%s' failed", serialdev); + + if (verbose) + fprintf(stderr, "Done.\n"); + + return (0); +} diff --git a/qemu/roms/u-boot/tools/gdb/remote.c b/qemu/roms/u-boot/tools/gdb/remote.c new file mode 100644 index 000000000..f3681043f --- /dev/null +++ b/qemu/roms/u-boot/tools/gdb/remote.c @@ -0,0 +1,916 @@ +/* + * taken from gdb/remote.c + * + * I am only interested in the write to memory stuff - everything else + * has been ripped out + * + * all the copyright notices etc have been left in + */ + +/* enough so that it will compile */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +/*nicked from gcc..*/ + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) +#include <alloca.h> +#else /* not sparc */ +#if defined (MSDOS) && !defined (__TURBOC__) +#include <malloc.h> +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +#include <malloc.h> + #pragma alloca +#else /* not MSDOS, __TURBOC__, or _AIX */ +#ifdef __hpux +#endif /* __hpux */ +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc. */ +#endif /* not GNU C. */ +#ifdef __cplusplus +extern "C" { +#endif + void* alloca(size_t); +#ifdef __cplusplus +} +#endif +#endif /* alloca not defined. */ + + +#include "serial.h" +#include "error.h" +#include "remote.h" +#define REGISTER_BYTES 0 +#define fprintf_unfiltered fprintf +#define fprintf_filtered fprintf +#define fputs_unfiltered fputs +#define fputs_filtered fputs +#define fputc_unfiltered fputc +#define fputc_filtered fputc +#define printf_unfiltered printf +#define printf_filtered printf +#define puts_unfiltered puts +#define puts_filtered puts +#define putchar_unfiltered putchar +#define putchar_filtered putchar +#define fputstr_unfiltered(a,b,c) fputs((a), (c)) +#define gdb_stdlog stderr +#define SERIAL_READCHAR(fd,timo) serialreadchar((fd), (timo)) +#define SERIAL_WRITE(fd, addr, len) serialwrite((fd), (addr), (len)) +#define error Error +#define perror_with_name Perror +#define gdb_flush fflush +#define max(a,b) (((a)>(b))?(a):(b)) +#define min(a,b) (((a)<(b))?(a):(b)) +#define target_mourn_inferior() {} +#define ULONGEST unsigned long +#define CORE_ADDR unsigned long + +static int putpkt (char *); +static int putpkt_binary(char *, int); +static void getpkt (char *, int); + +static int remote_debug = 0, remote_register_buf_size = 0, watchdog = 0; + +int remote_desc = -1, remote_timeout = 10; + +static void +fputstrn_unfiltered(char *s, int n, int x, FILE *fp) +{ + while (n-- > 0) + fputc(*s++, fp); +} + +void +remote_reset(void) +{ + SERIAL_WRITE(remote_desc, "+", 1); +} + +void +remote_continue(void) +{ + putpkt("c"); +} + +/* Remote target communications for serial-line targets in custom GDB protocol + Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 98, 1999 + Free Software Foundation, Inc. + + This file is part of GDB. + + * SPDX-License-Identifier: GPL-2.0+ + */ +/* *INDENT-OFF* */ +/* Remote communication protocol. + + A debug packet whose contents are <data> + is encapsulated for transmission in the form: + + $ <data> # CSUM1 CSUM2 + + <data> must be ASCII alphanumeric and cannot include characters + '$' or '#'. If <data> starts with two characters followed by + ':', then the existing stubs interpret this as a sequence number. + + CSUM1 and CSUM2 are ascii hex representation of an 8-bit + checksum of <data>, the most significant nibble is sent first. + the hex digits 0-9,a-f are used. + + Receiver responds with: + + + - if CSUM is correct and ready for next packet + - - if CSUM is incorrect + + <data> is as follows: + Most values are encoded in ascii hex digits. Signal numbers are according + to the numbering in target.h. + + Request Packet + + set thread Hct... Set thread for subsequent operations. + c = 'c' for thread used in step and + continue; t... can be -1 for all + threads. + c = 'g' for thread used in other + operations. If zero, pick a thread, + any thread. + reply OK for success + ENN for an error. + + read registers g + reply XX....X Each byte of register data + is described by two hex digits. + Registers are in the internal order + for GDB, and the bytes in a register + are in the same order the machine uses. + or ENN for an error. + + write regs GXX..XX Each byte of register data + is described by two hex digits. + reply OK for success + ENN for an error + + write reg Pn...=r... Write register n... with value r..., + which contains two hex digits for each + byte in the register (target byte + order). + reply OK for success + ENN for an error + (not supported by all stubs). + + read mem mAA..AA,LLLL AA..AA is address, LLLL is length. + reply XX..XX XX..XX is mem contents + Can be fewer bytes than requested + if able to read only part of the data. + or ENN NN is errno + + write mem MAA..AA,LLLL:XX..XX + AA..AA is address, + LLLL is number of bytes, + XX..XX is data + reply OK for success + ENN for an error (this includes the case + where only part of the data was + written). + + write mem XAA..AA,LLLL:XX..XX + (binary) AA..AA is address, + LLLL is number of bytes, + XX..XX is binary data + reply OK for success + ENN for an error + + continue cAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + step sAA..AA AA..AA is address to resume + If AA..AA is omitted, + resume at same address. + + continue with Csig;AA..AA Continue with signal sig (hex signal + signal number). If ;AA..AA is omitted, + resume at same address. + + step with Ssig;AA..AA Like 'C' but step not continue. + signal + + last signal ? Reply the current reason for stopping. + This is the same reply as is generated + for step or cont : SAA where AA is the + signal number. + + detach D Reply OK. + + There is no immediate reply to step or cont. + The reply comes when the machine stops. + It is SAA AA is the signal number. + + or... TAAn...:r...;n...:r...;n...:r...; + AA = signal number + n... = register number (hex) + r... = register contents + n... = `thread' + r... = thread process ID. This is + a hex integer. + n... = other string not starting + with valid hex digit. + gdb should ignore this n,r pair + and go on to the next. This way + we can extend the protocol. + or... WAA The process exited, and AA is + the exit status. This is only + applicable for certains sorts of + targets. + or... XAA The process terminated with signal + AA. + or (obsolete) NAA;tttttttt;dddddddd;bbbbbbbb + AA = signal number + tttttttt = address of symbol "_start" + dddddddd = base of data section + bbbbbbbb = base of bss section. + Note: only used by Cisco Systems + targets. The difference between this + reply and the "qOffsets" query is that + the 'N' packet may arrive spontaneously + whereas the 'qOffsets' is a query + initiated by the host debugger. + or... OXX..XX XX..XX is hex encoding of ASCII data. This + can happen at any time while the + program is running and the debugger + should continue to wait for + 'W', 'T', etc. + + thread alive TXX Find out if the thread XX is alive. + reply OK thread is still alive + ENN thread is dead + + remote restart RXX Restart the remote server + + extended ops ! Use the extended remote protocol. + Sticky -- only needs to be set once. + + kill request k + + toggle debug d toggle debug flag (see 386 & 68k stubs) + reset r reset -- see sparc stub. + reserved <other> On other requests, the stub should + ignore the request and send an empty + response ($#<checksum>). This way + we can extend the protocol and GDB + can tell whether the stub it is + talking to uses the old or the new. + search tAA:PP,MM Search backwards starting at address + AA for a match with pattern PP and + mask MM. PP and MM are 4 bytes. + Not supported by all stubs. + + general query qXXXX Request info about XXXX. + general set QXXXX=yyyy Set value of XXXX to yyyy. + query sect offs qOffsets Get section offsets. Reply is + Text=xxx;Data=yyy;Bss=zzz + + Responses can be run-length encoded to save space. A '*' means that + the next character is an ASCII encoding giving a repeat count which + stands for that many repititions of the character preceding the '*'. + The encoding is n+29, yielding a printable character where n >=3 + (which is where rle starts to win). Don't use an n > 126. + + So + "0* " means the same as "0000". */ +/* *INDENT-ON* */ + +/* This variable (available to the user via "set remotebinarydownload") + dictates whether downloads are sent in binary (via the 'X' packet). + We assume that the stub can, and attempt to do it. This will be cleared if + the stub does not understand it. This switch is still needed, though + in cases when the packet is supported in the stub, but the connection + does not allow it (i.e., 7-bit serial connection only). */ +static int remote_binary_download = 1; + +/* Have we already checked whether binary downloads work? */ +static int remote_binary_checked; + +/* Maximum number of bytes to read/write at once. The value here + is chosen to fill up a packet (the headers account for the 32). */ +#define MAXBUFBYTES(N) (((N)-32)/2) + +/* Having this larger than 400 causes us to be incompatible with m68k-stub.c + and i386-stub.c. Normally, no one would notice because it only matters + for writing large chunks of memory (e.g. in downloads). Also, this needs + to be more than 400 if required to hold the registers (see below, where + we round it up based on REGISTER_BYTES). */ +/* Round up PBUFSIZ to hold all the registers, at least. */ +#define PBUFSIZ ((REGISTER_BYTES > MAXBUFBYTES (400)) \ + ? (REGISTER_BYTES * 2 + 32) \ + : 400) + + +/* This variable sets the number of bytes to be written to the target + in a single packet. Normally PBUFSIZ is satisfactory, but some + targets need smaller values (perhaps because the receiving end + is slow). */ + +static int remote_write_size = 0x7fffffff; + +/* This variable sets the number of bits in an address that are to be + sent in a memory ("M" or "m") packet. Normally, after stripping + leading zeros, the entire address would be sent. This variable + restricts the address to REMOTE_ADDRESS_SIZE bits. HISTORY: The + initial implementation of remote.c restricted the address sent in + memory packets to ``host::sizeof long'' bytes - (typically 32 + bits). Consequently, for 64 bit targets, the upper 32 bits of an + address was never sent. Since fixing this bug may cause a break in + some remote targets this variable is principly provided to + facilitate backward compatibility. */ + +static int remote_address_size; + +/* Convert hex digit A to a number. */ + +static int +fromhex (int a) +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else if (a >= 'A' && a <= 'F') + return a - 'A' + 10; + else { + error ("Reply contains invalid hex digit %d", a); + return -1; + } +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (int nib) +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +/* Return the number of hex digits in num. */ + +static int +hexnumlen (ULONGEST num) +{ + int i; + + for (i = 0; num != 0; i++) + num >>= 4; + + return max (i, 1); +} + +/* Set BUF to the hex digits representing NUM. */ + +static int +hexnumstr (char *buf, ULONGEST num) +{ + int i; + int len = hexnumlen (num); + + buf[len] = '\0'; + + for (i = len - 1; i >= 0; i--) + { + buf[i] = "0123456789abcdef"[(num & 0xf)]; + num >>= 4; + } + + return len; +} + +/* Mask all but the least significant REMOTE_ADDRESS_SIZE bits. */ + +static CORE_ADDR +remote_address_masked (CORE_ADDR addr) +{ + if (remote_address_size > 0 + && remote_address_size < (sizeof (ULONGEST) * 8)) + { + /* Only create a mask when that mask can safely be constructed + in a ULONGEST variable. */ + ULONGEST mask = 1; + mask = (mask << remote_address_size) - 1; + addr &= mask; + } + return addr; +} + +/* Determine whether the remote target supports binary downloading. + This is accomplished by sending a no-op memory write of zero length + to the target at the specified address. It does not suffice to send + the whole packet, since many stubs strip the eighth bit and subsequently + compute a wrong checksum, which causes real havoc with remote_write_bytes. + + NOTE: This can still lose if the serial line is not eight-bit clean. In + cases like this, the user should clear "remotebinarydownload". */ +static void +check_binary_download (CORE_ADDR addr) +{ + if (remote_binary_download && !remote_binary_checked) + { + char *buf = alloca (PBUFSIZ); + char *p; + remote_binary_checked = 1; + + p = buf; + *p++ = 'X'; + p += hexnumstr (p, (ULONGEST) addr); + *p++ = ','; + p += hexnumstr (p, (ULONGEST) 0); + *p++ = ':'; + *p = '\0'; + + putpkt_binary (buf, (int) (p - buf)); + getpkt (buf, 0); + + if (buf[0] == '\0') + remote_binary_download = 0; + } + + if (remote_debug) + { + if (remote_binary_download) + fprintf_unfiltered (gdb_stdlog, + "binary downloading suppported by target\n"); + else + fprintf_unfiltered (gdb_stdlog, + "binary downloading NOT suppported by target\n"); + } +} + +/* Write memory data directly to the remote machine. + This does not inform the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + Returns number of bytes transferred, or 0 for error. */ + +int +remote_write_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + unsigned char *buf = alloca (PBUFSIZ); + int max_buf_size; /* Max size of packet output buffer */ + int origlen; + extern int verbose; + + /* Verify that the target can support a binary download */ + check_binary_download (memaddr); + + /* Chop the transfer down if necessary */ + + max_buf_size = min (remote_write_size, PBUFSIZ); + if (remote_register_buf_size != 0) + max_buf_size = min (max_buf_size, remote_register_buf_size); + + /* Subtract header overhead from max payload size - $M<memaddr>,<len>:#nn */ + max_buf_size -= 2 + hexnumlen (memaddr + len - 1) + 1 + hexnumlen (len) + 4; + + origlen = len; + while (len > 0) + { + unsigned char *p, *plen; + int todo; + int i; + + /* construct "M"<memaddr>","<len>":" */ + /* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */ + memaddr = remote_address_masked (memaddr); + p = buf; + if (remote_binary_download) + { + *p++ = 'X'; + todo = min (len, max_buf_size); + } + else + { + *p++ = 'M'; + todo = min (len, max_buf_size / 2); /* num bytes that will fit */ + } + + p += hexnumstr ((char *)p, (ULONGEST) memaddr); + *p++ = ','; + + plen = p; /* remember where len field goes */ + p += hexnumstr ((char *)p, (ULONGEST) todo); + *p++ = ':'; + *p = '\0'; + + /* We send target system values byte by byte, in increasing byte + addresses, each byte encoded as two hex characters (or one + binary character). */ + if (remote_binary_download) + { + int escaped = 0; + for (i = 0; + (i < todo) && (i + escaped) < (max_buf_size - 2); + i++) + { + switch (myaddr[i] & 0xff) + { + case '$': + case '#': + case 0x7d: + /* These must be escaped */ + escaped++; + *p++ = 0x7d; + *p++ = (myaddr[i] & 0xff) ^ 0x20; + break; + default: + *p++ = myaddr[i] & 0xff; + break; + } + } + + if (i < todo) + { + /* Escape chars have filled up the buffer prematurely, + and we have actually sent fewer bytes than planned. + Fix-up the length field of the packet. */ + + /* FIXME: will fail if new len is a shorter string than + old len. */ + + plen += hexnumstr ((char *)plen, (ULONGEST) i); + *plen++ = ':'; + } + } + else + { + for (i = 0; i < todo; i++) + { + *p++ = tohex ((myaddr[i] >> 4) & 0xf); + *p++ = tohex (myaddr[i] & 0xf); + } + *p = '\0'; + } + + putpkt_binary ((char *)buf, (int) (p - buf)); + getpkt ((char *)buf, 0); + + if (buf[0] == 'E') + { + /* There is no correspondance between what the remote protocol uses + for errors and errno codes. We would like a cleaner way of + representing errors (big enough to include errno codes, bfd_error + codes, and others). But for now just return EIO. */ + errno = EIO; + return 0; + } + + /* Increment by i, not by todo, in case escape chars + caused us to send fewer bytes than we'd planned. */ + myaddr += i; + memaddr += i; + len -= i; + + if (verbose) + putc('.', stderr); + } + return origlen; +} + +/* Stuff for dealing with the packets which are part of this protocol. + See comment at top of file for details. */ + +/* Read a single character from the remote end, masking it down to 7 bits. */ + +static int +readchar (int timeout) +{ + int ch; + + ch = SERIAL_READCHAR (remote_desc, timeout); + + switch (ch) + { + case SERIAL_EOF: + error ("Remote connection closed"); + case SERIAL_ERROR: + perror_with_name ("Remote communication error"); + case SERIAL_TIMEOUT: + return ch; + default: + return ch & 0x7f; + } +} + +static int +putpkt (buf) + char *buf; +{ + return putpkt_binary (buf, strlen (buf)); +} + +/* Send a packet to the remote machine, with error checking. The data + of the packet is in BUF. The string in BUF can be at most PBUFSIZ - 5 + to account for the $, # and checksum, and for a possible /0 if we are + debugging (remote_debug) and want to print the sent packet as a string */ + +static int +putpkt_binary (buf, cnt) + char *buf; + int cnt; +{ + int i; + unsigned char csum = 0; + char *buf2 = alloca (PBUFSIZ); + char *junkbuf = alloca (PBUFSIZ); + + int ch; + int tcount = 0; + char *p; + + /* Copy the packet into buffer BUF2, encapsulating it + and giving it a checksum. */ + + if (cnt > BUFSIZ - 5) /* Prosanity check */ + abort (); + + p = buf2; + *p++ = '$'; + + for (i = 0; i < cnt; i++) + { + csum += buf[i]; + *p++ = buf[i]; + } + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + /* Send it over and over until we get a positive ack. */ + + while (1) + { + int started_error_output = 0; + + if (remote_debug) + { + *p = '\0'; + fprintf_unfiltered (gdb_stdlog, "Sending packet: "); + fputstrn_unfiltered (buf2, p - buf2, 0, gdb_stdlog); + fprintf_unfiltered (gdb_stdlog, "..."); + gdb_flush (gdb_stdlog); + } + if (SERIAL_WRITE (remote_desc, buf2, p - buf2)) + perror_with_name ("putpkt: write failed"); + + /* read until either a timeout occurs (-2) or '+' is read */ + while (1) + { + ch = readchar (remote_timeout); + + if (remote_debug) + { + switch (ch) + { + case '+': + case SERIAL_TIMEOUT: + case '$': + if (started_error_output) + { + putchar_unfiltered ('\n'); + started_error_output = 0; + } + } + } + + switch (ch) + { + case '+': + if (remote_debug) + fprintf_unfiltered (gdb_stdlog, "Ack\n"); + return 1; + case SERIAL_TIMEOUT: + tcount++; + if (tcount > 3) + return 0; + break; /* Retransmit buffer */ + case '$': + { + /* It's probably an old response, and we're out of sync. + Just gobble up the packet and ignore it. */ + getpkt (junkbuf, 0); + continue; /* Now, go look for + */ + } + default: + if (remote_debug) + { + if (!started_error_output) + { + started_error_output = 1; + fprintf_unfiltered (gdb_stdlog, "putpkt: Junk: "); + } + fputc_unfiltered (ch & 0177, gdb_stdlog); + } + continue; + } + break; /* Here to retransmit */ + } + +#if 0 + /* This is wrong. If doing a long backtrace, the user should be + able to get out next time we call QUIT, without anything as + violent as interrupt_query. If we want to provide a way out of + here without getting to the next QUIT, it should be based on + hitting ^C twice as in remote_wait. */ + if (quit_flag) + { + quit_flag = 0; + interrupt_query (); + } +#endif + } +} + +/* Come here after finding the start of the frame. Collect the rest + into BUF, verifying the checksum, length, and handling run-length + compression. Returns 0 on any error, 1 on success. */ + +static int +read_frame (char *buf) +{ + unsigned char csum; + char *bp; + int c; + + csum = 0; + bp = buf; + + while (1) + { + c = readchar (remote_timeout); + + switch (c) + { + case SERIAL_TIMEOUT: + if (remote_debug) + fputs_filtered ("Timeout in mid-packet, retrying\n", gdb_stdlog); + return 0; + case '$': + if (remote_debug) + fputs_filtered ("Saw new packet start in middle of old one\n", + gdb_stdlog); + return 0; /* Start a new packet, count retries */ + case '#': + { + unsigned char pktcsum; + + *bp = '\000'; + + pktcsum = fromhex (readchar (remote_timeout)) << 4; + pktcsum |= fromhex (readchar (remote_timeout)); + + if (csum == pktcsum) + { + return 1; + } + + if (remote_debug) + { + fprintf_filtered (gdb_stdlog, + "Bad checksum, sentsum=0x%x, csum=0x%x, buf=", + pktcsum, csum); + fputs_filtered (buf, gdb_stdlog); + fputs_filtered ("\n", gdb_stdlog); + } + return 0; + } + case '*': /* Run length encoding */ + csum += c; + c = readchar (remote_timeout); + csum += c; + c = c - ' ' + 3; /* Compute repeat count */ + + if (c > 0 && c < 255 && bp + c - 1 < buf + PBUFSIZ - 1) + { + memset (bp, *(bp - 1), c); + bp += c; + continue; + } + + *bp = '\0'; + printf_filtered ("Repeat count %d too large for buffer: ", c); + puts_filtered (buf); + puts_filtered ("\n"); + return 0; + default: + if (bp < buf + PBUFSIZ - 1) + { + *bp++ = c; + csum += c; + continue; + } + + *bp = '\0'; + puts_filtered ("Remote packet too long: "); + puts_filtered (buf); + puts_filtered ("\n"); + + return 0; + } + } +} + +/* Read a packet from the remote machine, with error checking, and + store it in BUF. BUF is expected to be of size PBUFSIZ. If + FOREVER, wait forever rather than timing out; this is used while + the target is executing user code. */ + +static void +getpkt (buf, forever) + char *buf; + int forever; +{ + int c; + int tries; + int timeout; + int val; + + strcpy (buf, "timeout"); + + if (forever) + { + timeout = watchdog > 0 ? watchdog : -1; + } + + else + timeout = remote_timeout; + +#define MAX_TRIES 3 + + for (tries = 1; tries <= MAX_TRIES; tries++) + { + /* This can loop forever if the remote side sends us characters + continuously, but if it pauses, we'll get a zero from readchar + because of timeout. Then we'll count that as a retry. */ + + /* Note that we will only wait forever prior to the start of a packet. + After that, we expect characters to arrive at a brisk pace. They + should show up within remote_timeout intervals. */ + + do + { + c = readchar (timeout); + + if (c == SERIAL_TIMEOUT) + { + if (forever) /* Watchdog went off. Kill the target. */ + { + target_mourn_inferior (); + error ("Watchdog has expired. Target detached.\n"); + } + if (remote_debug) + fputs_filtered ("Timed out.\n", gdb_stdlog); + goto retry; + } + } + while (c != '$'); + + /* We've found the start of a packet, now collect the data. */ + + val = read_frame (buf); + + if (val == 1) + { + if (remote_debug) + { + fprintf_unfiltered (gdb_stdlog, "Packet received: "); + fputstr_unfiltered (buf, 0, gdb_stdlog); + fprintf_unfiltered (gdb_stdlog, "\n"); + } + SERIAL_WRITE (remote_desc, "+", 1); + return; + } + + /* Try the whole thing again. */ + retry: + SERIAL_WRITE (remote_desc, "-", 1); + } + + /* We have tried hard enough, and just can't receive the packet. Give up. */ + + printf_unfiltered ("Ignoring packet error, continuing...\n"); + SERIAL_WRITE (remote_desc, "+", 1); +} diff --git a/qemu/roms/u-boot/tools/gdb/remote.h b/qemu/roms/u-boot/tools/gdb/remote.h new file mode 100644 index 000000000..df6b06988 --- /dev/null +++ b/qemu/roms/u-boot/tools/gdb/remote.h @@ -0,0 +1,12 @@ +/* + * (C) Copyright 2000 + * Murray Jensen <Murray.Jensen@csiro.au> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +extern int remote_desc, remote_timeout; + +extern void remote_reset(void); +extern void remote_continue(void); +extern int remote_write_bytes(unsigned long, char *, int); diff --git a/qemu/roms/u-boot/tools/gdb/serial.c b/qemu/roms/u-boot/tools/gdb/serial.c new file mode 100644 index 000000000..709f8cef7 --- /dev/null +++ b/qemu/roms/u-boot/tools/gdb/serial.c @@ -0,0 +1,133 @@ +/* + * (C) Copyright 2000 + * Murray Jensen <Murray.Jensen@csiro.au> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <sys/time.h> +#include "serial.h" + +#if defined(__sun__) || \ + defined(__OpenBSD__) || \ + defined(__FreeBSD__) || \ + defined(__NetBSD__) || \ + defined(__APPLE__) +static struct termios tios = { BRKINT, 0, B115200|CS8|CREAD, 0, { 0 } }; +#else +static struct termios tios = { BRKINT, 0, B115200|CS8|CREAD, 0, 0 }; +#endif + +static struct speedmap { + char *str; + speed_t val; +} speedmap[] = { + { "50", B50 }, { "75", B75 }, { "110", B110 }, + { "134", B134 }, { "150", B150 }, { "200", B200 }, + { "300", B300 }, { "600", B600 }, { "1200", B1200 }, + { "1800", B1800 }, { "2400", B2400 }, { "4800", B4800 }, + { "9600", B9600 }, { "19200", B19200 }, { "38400", B38400 }, + { "57600", B57600 }, +#ifdef B76800 + { "76800", B76800 }, +#endif + { "115200", B115200 }, +#ifdef B153600 + { "153600", B153600 }, +#endif + { "230400", B230400 }, +#ifdef B307200 + { "307200", B307200 }, +#endif +#ifdef B460800 + { "460800", B460800 } +#endif +}; +static int nspeeds = sizeof speedmap / sizeof speedmap[0]; + +speed_t +cvtspeed(char *str) +{ + struct speedmap *smp = speedmap, *esmp = &speedmap[nspeeds]; + + while (smp < esmp) { + if (strcmp(str, smp->str) == 0) + return (smp->val); + smp++; + } + return B0; +} + +int +serialopen(char *device, speed_t speed) +{ + int fd; + + if (cfsetospeed(&tios, speed) < 0) + return -1; + + if ((fd = open(device, O_RDWR)) < 0) + return -1; + + if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { + (void)close(fd); + return -1; + } + + return fd; +} + +int +serialreadchar(int fd, int timeout) +{ + fd_set fds; + struct timeval tv; + int n; + char ch; + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + /* this is a fucking horrible quick hack - fix this */ + + if ((n = select(fd + 1, &fds, 0, 0, &tv)) < 0) + return SERIAL_ERROR; + + if (n == 0) + return SERIAL_TIMEOUT; + + if ((n = read(fd, &ch, 1)) < 0) + return SERIAL_ERROR; + + if (n == 0) + return SERIAL_EOF; + + return ch; +} + +int +serialwrite(int fd, char *buf, int len) +{ + int n; + + do { + n = write(fd, buf, len); + if (n < 0) + return 1; + len -= n; + buf += n; + } while (len > 0); + return 0; +} + +int +serialclose(int fd) +{ + return close(fd); +} diff --git a/qemu/roms/u-boot/tools/gdb/serial.h b/qemu/roms/u-boot/tools/gdb/serial.h new file mode 100644 index 000000000..dc9d6b7e5 --- /dev/null +++ b/qemu/roms/u-boot/tools/gdb/serial.h @@ -0,0 +1,18 @@ +/* + * (C) Copyright 2000 + * Murray Jensen <Murray.Jensen@csiro.au> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <termios.h> + +#define SERIAL_ERROR -1 /* General error, see errno for details */ +#define SERIAL_TIMEOUT -2 +#define SERIAL_EOF -3 + +extern speed_t cvtspeed(char *); +extern int serialopen(char *, speed_t); +extern int serialreadchar(int, int); +extern int serialwrite(int, char *, int); +extern int serialclose(int); diff --git a/qemu/roms/u-boot/tools/gen_eth_addr.c b/qemu/roms/u-boot/tools/gen_eth_addr.c new file mode 100644 index 000000000..bf9d935ef --- /dev/null +++ b/qemu/roms/u-boot/tools/gen_eth_addr.c @@ -0,0 +1,34 @@ +/* + * (C) Copyright 2001 + * Murray Jensen <Murray.Jensen@cmst.csiro.au> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <time.h> + +int +main(int argc, char *argv[]) +{ + unsigned long ethaddr_low, ethaddr_high; + + srand(time(0) | getpid()); + + /* + * setting the 2nd LSB in the most significant byte of + * the address makes it a locally administered ethernet + * address + */ + ethaddr_high = (rand() & 0xfeff) | 0x0200; + ethaddr_low = rand(); + + printf("%02lx:%02lx:%02lx:%02lx:%02lx:%02lx\n", + ethaddr_high >> 8, ethaddr_high & 0xff, + ethaddr_low >> 24, (ethaddr_low >> 16) & 0xff, + (ethaddr_low >> 8) & 0xff, ethaddr_low & 0xff); + + return (0); +} diff --git a/qemu/roms/u-boot/tools/getline.c b/qemu/roms/u-boot/tools/getline.c new file mode 100644 index 000000000..f7dbcc9bf --- /dev/null +++ b/qemu/roms/u-boot/tools/getline.c @@ -0,0 +1,90 @@ +/* getline.c -- Replacement for GNU C library function getline + * + * Copyright (C) 1993, 1996, 2001, 2002 Free Software Foundation, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */ + +#include <assert.h> +#include <stdio.h> + +/* Always add at least this many bytes when extending the buffer. */ +#define MIN_CHUNK 64 + +/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR + + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from + malloc (or NULL), pointing to *N characters of space. It is realloc'd + as necessary. Return the number of characters read (not including the + null terminator), or -1 on error or EOF. + NOTE: There is another getstr() function declared in <curses.h>. */ +static int getstr(char **lineptr, size_t *n, FILE *stream, + char terminator, size_t offset) +{ + int nchars_avail; /* Allocated but unused chars in *LINEPTR. */ + char *read_pos; /* Where we're reading into *LINEPTR. */ + int ret; + + if (!lineptr || !n || !stream) + return -1; + + if (!*lineptr) { + *n = MIN_CHUNK; + *lineptr = malloc(*n); + if (!*lineptr) + return -1; + } + + nchars_avail = *n - offset; + read_pos = *lineptr + offset; + + for (;;) { + register int c = getc(stream); + + /* We always want at least one char left in the buffer, since we + always (unless we get an error while reading the first char) + NUL-terminate the line buffer. */ + + assert(*n - nchars_avail == read_pos - *lineptr); + if (nchars_avail < 2) { + if (*n > MIN_CHUNK) + *n *= 2; + else + *n += MIN_CHUNK; + + nchars_avail = *n + *lineptr - read_pos; + *lineptr = realloc(*lineptr, *n); + if (!*lineptr) + return -1; + read_pos = *n - nchars_avail + *lineptr; + assert(*n - nchars_avail == read_pos - *lineptr); + } + + if (c == EOF || ferror (stream)) { + /* Return partial line, if any. */ + if (read_pos == *lineptr) + return -1; + else + break; + } + + *read_pos++ = c; + nchars_avail--; + + if (c == terminator) + /* Return the line. */ + break; + } + + /* Done - NUL terminate and return the number of chars read. */ + *read_pos = '\0'; + + ret = read_pos - (*lineptr + offset); + return ret; +} + +int getline (char **lineptr, size_t *n, FILE *stream) +{ + return getstr(lineptr, n, stream, '\n', 0); +} diff --git a/qemu/roms/u-boot/tools/getline.h b/qemu/roms/u-boot/tools/getline.h new file mode 100644 index 000000000..a2f35b92b --- /dev/null +++ b/qemu/roms/u-boot/tools/getline.h @@ -0,0 +1 @@ +int getline(char **lineptr, size_t *n, FILE *stream); diff --git a/qemu/roms/u-boot/tools/gpheader.h b/qemu/roms/u-boot/tools/gpheader.h new file mode 100644 index 000000000..63a28a264 --- /dev/null +++ b/qemu/roms/u-boot/tools/gpheader.h @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2014 + * Texas Instruments Incorporated + * Refactored common functions in to gpimage-common.c. Include this common + * header file + * + * (C) Copyright 2010 + * Linaro LTD, www.linaro.org + * Author: John Rigby <john.rigby@linaro.org> + * Based on TI's signGP.c + * + * (C) Copyright 2009 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * (C) Copyright 2008 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _GPIMAGE_H_ +#define _GPIMAGE_H_ + +/* common headers for gpimage and omapimage formats */ +struct gp_header { + uint32_t size; + uint32_t load_addr; +}; +#define GPIMAGE_HDR_SIZE (sizeof(struct gp_header)) + +/* common functions across gpimage and omapimage handlers */ +int valid_gph_size(uint32_t size); +int valid_gph_load_addr(uint32_t load_addr); +int gph_verify_header(struct gp_header *gph, int be); +void gph_print_header(const struct gp_header *gph, int be); +void gph_set_header(struct gp_header *gph, uint32_t size, uint32_t load_addr, + int be); +int gpimage_check_params(struct image_tool_params *params); +#endif diff --git a/qemu/roms/u-boot/tools/gpimage-common.c b/qemu/roms/u-boot/tools/gpimage-common.c new file mode 100644 index 000000000..b343a3aa8 --- /dev/null +++ b/qemu/roms/u-boot/tools/gpimage-common.c @@ -0,0 +1,80 @@ +/* + * (C) Copyright 2014 + * Texas Instruments Incorporated + * Refactored common functions in to gpimage-common.c. + * + * (C) Copyright 2010 + * Linaro LTD, www.linaro.org + * Author: John Rigby <john.rigby@linaro.org> + * Based on TI's signGP.c + * + * (C) Copyright 2009 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * (C) Copyright 2008 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include <compiler.h> +#include <image.h> +#include "gpheader.h" + +/* Helper to convert size and load_addr to big endian */ +void to_be32(uint32_t *gph_size, uint32_t *gph_load_addr) +{ + *gph_size = cpu_to_be32(*gph_size); + *gph_load_addr = cpu_to_be32(*gph_load_addr); +} + +int gph_verify_header(struct gp_header *gph, int be) +{ + uint32_t gph_size = gph->size, gph_load_addr = gph->load_addr; + + if (be) + to_be32(&gph_size, &gph_load_addr); + + if (!gph_size || !gph_load_addr) + return -1; + + return 0; +} + +void gph_print_header(const struct gp_header *gph, int be) +{ + uint32_t gph_size = gph->size, gph_load_addr = gph->load_addr; + + if (be) + to_be32(&gph_size, &gph_load_addr); + + if (!gph_size) { + fprintf(stderr, "Error: invalid image size %x\n", gph_size); + exit(EXIT_FAILURE); + } + + if (!gph_load_addr) { + fprintf(stderr, "Error: invalid image load address %x\n", + gph_load_addr); + exit(EXIT_FAILURE); + } + printf("GP Header: Size %x LoadAddr %x\n", gph_size, gph_load_addr); +} + +void gph_set_header(struct gp_header *gph, uint32_t size, uint32_t load_addr, + int be) +{ + gph->size = size; + gph->load_addr = load_addr; + if (be) + to_be32(&gph->size, &gph->load_addr); +} + +int gpimage_check_params(struct image_tool_params *params) +{ + return (params->dflag && (params->fflag || params->lflag)) || + (params->fflag && (params->dflag || params->lflag)) || + (params->lflag && (params->dflag || params->fflag)); +} diff --git a/qemu/roms/u-boot/tools/gpimage.c b/qemu/roms/u-boot/tools/gpimage.c new file mode 100644 index 000000000..1cabb5b61 --- /dev/null +++ b/qemu/roms/u-boot/tools/gpimage.c @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2014 + * Texas Instruments Incorporated + * Add gpimage format for keystone devices to format spl image. This is + * Based on omapimage.c + * + * (C) Copyright 2010 + * Linaro LTD, www.linaro.org + * Author: John Rigby <john.rigby@linaro.org> + * Based on TI's signGP.c + * + * (C) Copyright 2009 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * (C) Copyright 2008 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include <compiler.h> +#include <image.h> +#include "gpheader.h" + +static uint8_t gpimage_header[GPIMAGE_HDR_SIZE]; + +/* to be in keystone gpimage */ +static int gpimage_check_image_types(uint8_t type) +{ + if (type == IH_TYPE_GPIMAGE) + return EXIT_SUCCESS; + return EXIT_FAILURE; +} + +static int gpimage_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + struct gp_header *gph = (struct gp_header *)ptr; + + return gph_verify_header(gph, 1); +} + +static void gpimage_print_header(const void *ptr) +{ + const struct gp_header *gph = (struct gp_header *)ptr; + + gph_print_header(gph, 1); +} + +static void gpimage_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + struct gp_header *gph = (struct gp_header *)ptr; + + gph_set_header(gph, sbuf->st_size - GPIMAGE_HDR_SIZE, params->addr, 1); +} + +/* + * gpimage parameters + */ +static struct image_type_params gpimage_params = { + .name = "TI KeyStone GP Image support", + .header_size = GPIMAGE_HDR_SIZE, + .hdr = (void *)&gpimage_header, + .check_image_type = gpimage_check_image_types, + .verify_header = gpimage_verify_header, + .print_header = gpimage_print_header, + .set_header = gpimage_set_header, + .check_params = gpimage_check_params, +}; + +void init_gpimage_type(void) +{ + register_image_type(&gpimage_params); +} diff --git a/qemu/roms/u-boot/tools/image-fit.c b/qemu/roms/u-boot/tools/image-fit.c new file mode 100644 index 000000000..037e5cc8d --- /dev/null +++ b/qemu/roms/u-boot/tools/image-fit.c @@ -0,0 +1 @@ +#include "../common/image-fit.c" diff --git a/qemu/roms/u-boot/tools/image-host.c b/qemu/roms/u-boot/tools/image-host.c new file mode 100644 index 000000000..651f1c2f8 --- /dev/null +++ b/qemu/roms/u-boot/tools/image-host.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "mkimage.h" +#include <image.h> +#include <version.h> + +/** + * fit_set_hash_value - set hash value in requested has node + * @fit: pointer to the FIT format image header + * @noffset: hash node offset + * @value: hash value to be set + * @value_len: hash value length + * + * fit_set_hash_value() attempts to set hash value in a node at offset + * given and returns operation status to the caller. + * + * returns + * 0, on success + * -1, on failure + */ +static int fit_set_hash_value(void *fit, int noffset, uint8_t *value, + int value_len) +{ + int ret; + + ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); + if (ret) { + printf("Can't set hash '%s' property for '%s' node(%s)\n", + FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL), + fdt_strerror(ret)); + return -1; + } + + return 0; +} + +/** + * fit_image_process_hash - Process a single subnode of the images/ node + * + * Check each subnode and process accordingly. For hash nodes we generate + * a hash of the supplised data and store it in the node. + * + * @fit: pointer to the FIT format image header + * @image_name: name of image being processes (used to display errors) + * @noffset: subnode offset + * @data: data to process + * @size: size of data in bytes + * @return 0 if ok, -1 on error + */ +static int fit_image_process_hash(void *fit, const char *image_name, + int noffset, const void *data, size_t size) +{ + uint8_t value[FIT_MAX_HASH_LEN]; + const char *node_name; + int value_len; + char *algo; + + node_name = fit_get_name(fit, noffset, NULL); + + if (fit_image_hash_get_algo(fit, noffset, &algo)) { + printf("Can't get hash algo property for '%s' hash node in '%s' image node\n", + node_name, image_name); + return -1; + } + + if (calculate_hash(data, size, algo, value, &value_len)) { + printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n", + algo, node_name, image_name); + return -1; + } + + if (fit_set_hash_value(fit, noffset, value, value_len)) { + printf("Can't set hash value for '%s' hash node in '%s' image node\n", + node_name, image_name); + return -1; + } + + return 0; +} + +/** + * fit_image_write_sig() - write the signature to a FIT + * + * This writes the signature and signer data to the FIT. + * + * @fit: pointer to the FIT format image header + * @noffset: hash node offset + * @value: signature value to be set + * @value_len: signature value length + * @comment: Text comment to write (NULL for none) + * + * returns + * 0, on success + * -FDT_ERR_..., on failure + */ +static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, + int value_len, const char *comment, const char *region_prop, + int region_proplen) +{ + int string_size; + int ret; + + /* + * Get the current string size, before we update the FIT and add + * more + */ + string_size = fdt_size_dt_strings(fit); + + ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); + if (!ret) { + ret = fdt_setprop_string(fit, noffset, "signer-name", + "mkimage"); + } + if (!ret) { + ret = fdt_setprop_string(fit, noffset, "signer-version", + PLAIN_VERSION); + } + if (comment && !ret) + ret = fdt_setprop_string(fit, noffset, "comment", comment); + if (!ret) + ret = fit_set_timestamp(fit, noffset, time(NULL)); + if (region_prop && !ret) { + uint32_t strdata[2]; + + ret = fdt_setprop(fit, noffset, "hashed-nodes", + region_prop, region_proplen); + strdata[0] = 0; + strdata[1] = cpu_to_fdt32(string_size); + if (!ret) { + ret = fdt_setprop(fit, noffset, "hashed-strings", + strdata, sizeof(strdata)); + } + } + + return ret; +} + +static int fit_image_setup_sig(struct image_sign_info *info, + const char *keydir, void *fit, const char *image_name, + int noffset, const char *require_keys) +{ + const char *node_name; + char *algo_name; + + node_name = fit_get_name(fit, noffset, NULL); + if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { + printf("Can't get algo property for '%s' signature node in '%s' image node\n", + node_name, image_name); + return -1; + } + + memset(info, '\0', sizeof(*info)); + info->keydir = keydir; + info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info->fit = fit; + info->node_offset = noffset; + info->algo = image_get_sig_algo(algo_name); + info->require_keys = require_keys; + if (!info->algo) { + printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", + algo_name, node_name, image_name); + return -1; + } + + return 0; +} + +/** + * fit_image_process_sig- Process a single subnode of the images/ node + * + * Check each subnode and process accordingly. For signature nodes we + * generate a signed hash of the supplised data and store it in the node. + * + * @keydir: Directory containing keys to use for signing + * @keydest: Destination FDT blob to write public keys into + * @fit: pointer to the FIT format image header + * @image_name: name of image being processes (used to display errors) + * @noffset: subnode offset + * @data: data to process + * @size: size of data in bytes + * @comment: Comment to add to signature nodes + * @require_keys: Mark all keys as 'required' + * @return 0 if ok, -1 on error + */ +static int fit_image_process_sig(const char *keydir, void *keydest, + void *fit, const char *image_name, + int noffset, const void *data, size_t size, + const char *comment, int require_keys) +{ + struct image_sign_info info; + struct image_region region; + const char *node_name; + uint8_t *value; + uint value_len; + int ret; + + if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, + require_keys ? "image" : NULL)) + return -1; + + node_name = fit_get_name(fit, noffset, NULL); + region.data = data; + region.size = size; + ret = info.algo->sign(&info, ®ion, 1, &value, &value_len); + if (ret) { + printf("Failed to sign '%s' signature node in '%s' image node: %d\n", + node_name, image_name, ret); + + /* We allow keys to be missing */ + if (ret == -ENOENT) + return 0; + return -1; + } + + ret = fit_image_write_sig(fit, noffset, value, value_len, comment, + NULL, 0); + if (ret) { + printf("Can't write signature for '%s' signature node in '%s' image node: %s\n", + node_name, image_name, fdt_strerror(ret)); + return -1; + } + free(value); + + /* Get keyname again, as FDT has changed and invalidated our pointer */ + info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + + /* Write the public key into the supplied FDT file */ + if (keydest && info.algo->add_verify_data(&info, keydest)) { + printf("Failed to add verification data for '%s' signature node in '%s' image node\n", + node_name, image_name); + return -1; + } + + return 0; +} + +/** + * fit_image_add_verification_data() - calculate/set verig. data for image node + * + * This adds hash and signature values for an component image node. + * + * All existing hash subnodes are checked, if algorithm property is set to + * one of the supported hash algorithms, hash value is computed and + * corresponding hash node property is set, for example: + * + * Input component image node structure: + * + * o image@1 (at image_noffset) + * | - data = [binary data] + * o hash@1 + * |- algo = "sha1" + * + * Output component image node structure: + * + * o image@1 (at image_noffset) + * | - data = [binary data] + * o hash@1 + * |- algo = "sha1" + * |- value = sha1(data) + * + * For signature details, please see doc/uImage.FIT/signature.txt + * + * @keydir Directory containing *.key and *.crt files (or NULL) + * @keydest FDT Blob to write public keys into (NULL if none) + * @fit: Pointer to the FIT format image header + * @image_noffset: Requested component image node + * @comment: Comment to add to signature nodes + * @require_keys: Mark all keys as 'required' + * @return: 0 on success, <0 on failure + */ +int fit_image_add_verification_data(const char *keydir, void *keydest, + void *fit, int image_noffset, const char *comment, + int require_keys) +{ + const char *image_name; + const void *data; + size_t size; + int noffset; + + /* Get image data and data length */ + if (fit_image_get_data(fit, image_noffset, &data, &size)) { + printf("Can't get image data/size\n"); + return -1; + } + + image_name = fit_get_name(fit, image_noffset, NULL); + + /* Process all hash subnodes of the component image node */ + for (noffset = fdt_first_subnode(fit, image_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + const char *node_name; + int ret = 0; + + /* + * Check subnode name, must be equal to "hash" or "signature". + * Multiple hash nodes require unique unit node + * names, e.g. hash@1, hash@2, signature@1, etc. + */ + node_name = fit_get_name(fit, noffset, NULL); + if (!strncmp(node_name, FIT_HASH_NODENAME, + strlen(FIT_HASH_NODENAME))) { + ret = fit_image_process_hash(fit, image_name, noffset, + data, size); + } else if (IMAGE_ENABLE_SIGN && keydir && + !strncmp(node_name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + ret = fit_image_process_sig(keydir, keydest, + fit, image_name, noffset, data, size, + comment, require_keys); + } + if (ret) + return -1; + } + + return 0; +} + +struct strlist { + int count; + char **strings; +}; + +static void strlist_init(struct strlist *list) +{ + memset(list, '\0', sizeof(*list)); +} + +static void strlist_free(struct strlist *list) +{ + int i; + + for (i = 0; i < list->count; i++) + free(list->strings[i]); + free(list->strings); +} + +static int strlist_add(struct strlist *list, const char *str) +{ + char *dup; + + dup = strdup(str); + list->strings = realloc(list->strings, + (list->count + 1) * sizeof(char *)); + if (!list || !str) + return -1; + list->strings[list->count++] = dup; + + return 0; +} + +static const char *fit_config_get_image_list(void *fit, int noffset, + int *lenp, int *allow_missingp) +{ + static const char default_list[] = FIT_KERNEL_PROP "\0" + FIT_FDT_PROP; + const char *prop; + + /* If there is an "image" property, use that */ + prop = fdt_getprop(fit, noffset, "sign-images", lenp); + if (prop) { + *allow_missingp = 0; + return *lenp ? prop : NULL; + } + + /* Default image list */ + *allow_missingp = 1; + *lenp = sizeof(default_list); + + return default_list; +} + +static int fit_config_get_hash_list(void *fit, int conf_noffset, + int sig_offset, struct strlist *node_inc) +{ + int allow_missing; + const char *prop, *iname, *end; + const char *conf_name, *sig_name; + char name[200], path[200]; + int image_count; + int ret, len; + + conf_name = fit_get_name(fit, conf_noffset, NULL); + sig_name = fit_get_name(fit, sig_offset, NULL); + + /* + * Build a list of nodes we need to hash. We always need the root + * node and the configuration. + */ + strlist_init(node_inc); + snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name); + if (strlist_add(node_inc, "/") || + strlist_add(node_inc, name)) + goto err_mem; + + /* Get a list of images that we intend to sign */ + prop = fit_config_get_image_list(fit, sig_offset, &len, + &allow_missing); + if (!prop) + return 0; + + /* Locate the images */ + end = prop + len; + image_count = 0; + for (iname = prop; iname < end; iname += strlen(iname) + 1) { + int noffset; + int image_noffset; + int hash_count; + + image_noffset = fit_conf_get_prop_node(fit, conf_noffset, + iname); + if (image_noffset < 0) { + printf("Failed to find image '%s' in configuration '%s/%s'\n", + iname, conf_name, sig_name); + if (allow_missing) + continue; + + return -ENOENT; + } + + ret = fdt_get_path(fit, image_noffset, path, sizeof(path)); + if (ret < 0) + goto err_path; + if (strlist_add(node_inc, path)) + goto err_mem; + + snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, + conf_name); + + /* Add all this image's hashes */ + hash_count = 0; + for (noffset = fdt_first_subnode(fit, image_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + const char *name = fit_get_name(fit, noffset, NULL); + + if (strncmp(name, FIT_HASH_NODENAME, + strlen(FIT_HASH_NODENAME))) + continue; + ret = fdt_get_path(fit, noffset, path, sizeof(path)); + if (ret < 0) + goto err_path; + if (strlist_add(node_inc, path)) + goto err_mem; + hash_count++; + } + + if (!hash_count) { + printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n", + conf_name, sig_name, iname); + return -ENOMSG; + } + + image_count++; + } + + if (!image_count) { + printf("Failed to find any images for configuration '%s/%s'\n", + conf_name, sig_name); + return -ENOMSG; + } + + return 0; + +err_mem: + printf("Out of memory processing configuration '%s/%s'\n", conf_name, + sig_name); + return -ENOMEM; + +err_path: + printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n", + iname, conf_name, sig_name, fdt_strerror(ret)); + return -ENOENT; +} + +static int fit_config_get_data(void *fit, int conf_noffset, int noffset, + struct image_region **regionp, int *region_countp, + char **region_propp, int *region_proplen) +{ + char * const exc_prop[] = {"data"}; + struct strlist node_inc; + struct image_region *region; + struct fdt_region fdt_regions[100]; + const char *conf_name, *sig_name; + char path[200]; + int count, i; + char *region_prop; + int ret, len; + + conf_name = fit_get_name(fit, conf_noffset, NULL); + sig_name = fit_get_name(fit, conf_noffset, NULL); + debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); + + /* Get a list of nodes we want to hash */ + ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc); + if (ret) + return ret; + + /* Get a list of regions to hash */ + count = fdt_find_regions(fit, node_inc.strings, node_inc.count, + exc_prop, ARRAY_SIZE(exc_prop), + fdt_regions, ARRAY_SIZE(fdt_regions), + path, sizeof(path), 1); + if (count < 0) { + printf("Failed to hash configuration '%s/%s': %s\n", conf_name, + sig_name, fdt_strerror(ret)); + return -EIO; + } + if (count == 0) { + printf("No data to hash for configuration '%s/%s': %s\n", + conf_name, sig_name, fdt_strerror(ret)); + return -EINVAL; + } + + /* Build our list of data blocks */ + region = fit_region_make_list(fit, fdt_regions, count, NULL); + if (!region) { + printf("Out of memory hashing configuration '%s/%s'\n", + conf_name, sig_name); + return -ENOMEM; + } + + /* Create a list of all hashed properties */ + debug("Hash nodes:\n"); + for (i = len = 0; i < node_inc.count; i++) { + debug(" %s\n", node_inc.strings[i]); + len += strlen(node_inc.strings[i]) + 1; + } + region_prop = malloc(len); + if (!region_prop) { + printf("Out of memory setting up regions for configuration '%s/%s'\n", + conf_name, sig_name); + return -ENOMEM; + } + for (i = len = 0; i < node_inc.count; + len += strlen(node_inc.strings[i]) + 1, i++) + strcpy(region_prop + len, node_inc.strings[i]); + strlist_free(&node_inc); + + *region_countp = count; + *regionp = region; + *region_propp = region_prop; + *region_proplen = len; + + return 0; +} + +static int fit_config_process_sig(const char *keydir, void *keydest, + void *fit, const char *conf_name, int conf_noffset, + int noffset, const char *comment, int require_keys) +{ + struct image_sign_info info; + const char *node_name; + struct image_region *region; + char *region_prop; + int region_proplen; + int region_count; + uint8_t *value; + uint value_len; + int ret; + + node_name = fit_get_name(fit, noffset, NULL); + if (fit_config_get_data(fit, conf_noffset, noffset, ®ion, + ®ion_count, ®ion_prop, ®ion_proplen)) + return -1; + + if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, + require_keys ? "conf" : NULL)) + return -1; + + ret = info.algo->sign(&info, region, region_count, &value, &value_len); + free(region); + if (ret) { + printf("Failed to sign '%s' signature node in '%s' conf node\n", + node_name, conf_name); + + /* We allow keys to be missing */ + if (ret == -ENOENT) + return 0; + return -1; + } + + if (fit_image_write_sig(fit, noffset, value, value_len, comment, + region_prop, region_proplen)) { + printf("Can't write signature for '%s' signature node in '%s' conf node\n", + node_name, conf_name); + return -1; + } + free(value); + free(region_prop); + + /* Get keyname again, as FDT has changed and invalidated our pointer */ + info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + + /* Write the public key into the supplied FDT file */ + if (keydest && info.algo->add_verify_data(&info, keydest)) { + printf("Failed to add verification data for '%s' signature node in '%s' image node\n", + node_name, conf_name); + return -1; + } + + return 0; +} + +static int fit_config_add_verification_data(const char *keydir, void *keydest, + void *fit, int conf_noffset, const char *comment, + int require_keys) +{ + const char *conf_name; + int noffset; + + conf_name = fit_get_name(fit, conf_noffset, NULL); + + /* Process all hash subnodes of the configuration node */ + for (noffset = fdt_first_subnode(fit, conf_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + const char *node_name; + int ret = 0; + + node_name = fit_get_name(fit, noffset, NULL); + if (!strncmp(node_name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + ret = fit_config_process_sig(keydir, keydest, + fit, conf_name, conf_noffset, noffset, comment, + require_keys); + } + if (ret) + return ret; + } + + return 0; +} + +int fit_add_verification_data(const char *keydir, void *keydest, void *fit, + const char *comment, int require_keys) +{ + int images_noffset, confs_noffset; + int noffset; + int ret; + + /* Find images parent node offset */ + images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); + if (images_noffset < 0) { + printf("Can't find images parent node '%s' (%s)\n", + FIT_IMAGES_PATH, fdt_strerror(images_noffset)); + return images_noffset; + } + + /* Process its subnodes, print out component images details */ + for (noffset = fdt_first_subnode(fit, images_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + /* + * Direct child node of the images parent node, + * i.e. component image node. + */ + ret = fit_image_add_verification_data(keydir, keydest, + fit, noffset, comment, require_keys); + if (ret) + return ret; + } + + /* If there are no keys, we can't sign configurations */ + if (!IMAGE_ENABLE_SIGN || !keydir) + return 0; + + /* Find configurations parent node offset */ + confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); + if (confs_noffset < 0) { + printf("Can't find images parent node '%s' (%s)\n", + FIT_IMAGES_PATH, fdt_strerror(confs_noffset)); + return -ENOENT; + } + + /* Process its subnodes, print out component images details */ + for (noffset = fdt_first_subnode(fit, confs_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + ret = fit_config_add_verification_data(keydir, keydest, + fit, noffset, comment, + require_keys); + if (ret) + return ret; + } + + return 0; +} + +#ifdef CONFIG_FIT_SIGNATURE +int fit_check_sign(const void *working_fdt, const void *key) +{ + int cfg_noffset; + int ret; + + cfg_noffset = fit_conf_get_node(working_fdt, NULL); + if (!cfg_noffset) + return -1; + + ret = fit_config_verify(working_fdt, cfg_noffset); + return ret; +} +#endif diff --git a/qemu/roms/u-boot/tools/image-sig.c b/qemu/roms/u-boot/tools/image-sig.c new file mode 100644 index 000000000..e45419f32 --- /dev/null +++ b/qemu/roms/u-boot/tools/image-sig.c @@ -0,0 +1 @@ +#include "../common/image-sig.c" diff --git a/qemu/roms/u-boot/tools/image.c b/qemu/roms/u-boot/tools/image.c new file mode 100644 index 000000000..0f9bacc70 --- /dev/null +++ b/qemu/roms/u-boot/tools/image.c @@ -0,0 +1 @@ +#include "../common/image.c" diff --git a/qemu/roms/u-boot/tools/imagetool.c b/qemu/roms/u-boot/tools/imagetool.c new file mode 100644 index 000000000..da72115e5 --- /dev/null +++ b/qemu/roms/u-boot/tools/imagetool.c @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2013 + * + * Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" + +/* + * Callback function to register a image type within a tool + */ +static imagetool_register_t register_func; + +/* + * register_image_tool - + * + * The tool provides its own registration function in order to all image + * types initialize themselves. + */ +void register_image_tool(imagetool_register_t image_register) +{ + /* + * Save the image tool callback function. It will be used to register + * image types within that tool + */ + register_func = image_register; + + /* Init Freescale PBL Boot image generation/list support */ + init_pbl_image_type(); + /* Init Kirkwood Boot image generation/list support */ + init_kwb_image_type(); + /* Init Freescale imx Boot image generation/list support */ + init_imx_image_type(); + /* Init Freescale mxs Boot image generation/list support */ + init_mxs_image_type(); + /* Init FIT image generation/list support */ + init_fit_image_type(); + /* Init TI OMAP Boot image generation/list support */ + init_omap_image_type(); + /* Init Default image generation/list support */ + init_default_image_type(); + /* Init Davinci UBL support */ + init_ubl_image_type(); + /* Init Davinci AIS support */ + init_ais_image_type(); + /* Init TI Keystone boot image generation/list support */ + init_gpimage_type(); +} + +/* + * register_image_type - + * + * Register a image type within a tool + */ +void register_image_type(struct image_type_params *tparams) +{ + register_func(tparams); +} diff --git a/qemu/roms/u-boot/tools/imagetool.h b/qemu/roms/u-boot/tools/imagetool.h new file mode 100644 index 000000000..a3e9d302e --- /dev/null +++ b/qemu/roms/u-boot/tools/imagetool.h @@ -0,0 +1,174 @@ +/* + * (C) Copyright 2013 + * + * Written by Guilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _IMAGETOOL_H_ +#define _IMAGETOOL_H_ + +#include "os_support.h" +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> +#include <sha1.h> +#include "fdt_host.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define IH_ARCH_DEFAULT IH_ARCH_INVALID + +/* + * This structure defines all such variables those are initialized by + * mkimage and dumpimage main core and need to be referred by image + * type specific functions + */ +struct image_tool_params { + int dflag; + int eflag; + int fflag; + int iflag; + int lflag; + int pflag; + int vflag; + int xflag; + int skipcpy; + int os; + int arch; + int type; + int comp; + char *dtc; + unsigned int addr; + unsigned int ep; + char *imagename; + char *imagename2; + char *datafile; + char *imagefile; + char *cmdname; + const char *outfile; /* Output filename */ + const char *keydir; /* Directory holding private keys */ + const char *keydest; /* Destination .dtb for public key */ + const char *comment; /* Comment to add to signature node */ + int require_keys; /* 1 to mark signing keys as 'required' */ +}; + +/* + * image type specific variables and callback functions + */ +struct image_type_params { + /* name is an identification tag string for added support */ + char *name; + /* + * header size is local to the specific image type to be supported, + * mkimage core treats this as number of bytes + */ + uint32_t header_size; + /* Image type header pointer */ + void *hdr; + /* + * There are several arguments that are passed on the command line + * and are registered as flags in image_tool_params structure. + * This callback function can be used to check the passed arguments + * are in-lined with the image type to be supported + * + * Returns 1 if parameter check is successful + */ + int (*check_params) (struct image_tool_params *); + /* + * This function is used by list command (i.e. mkimage -l <filename>) + * image type verification code must be put here + * + * Returns 0 if image header verification is successful + * otherwise, returns respective negative error codes + */ + int (*verify_header) (unsigned char *, int, struct image_tool_params *); + /* Prints image information abstracting from image header */ + void (*print_header) (const void *); + /* + * The header or image contents need to be set as per image type to + * be generated using this callback function. + * further output file post processing (for ex. checksum calculation, + * padding bytes etc..) can also be done in this callback function. + */ + void (*set_header) (void *, struct stat *, int, + struct image_tool_params *); + /* + * This function is used by the command to retrieve a data file from + * the image (i.e. dumpimage -i <image> -p <position> <data_file>). + * Thus the code to extract a file from an image must be put here. + * + * Returns 0 if the file was successfully retrieved from the image, + * or a negative value on error. + */ + int (*extract_datafile) (void *, struct image_tool_params *); + /* + * Some image generation support for ex (default image type) supports + * more than one type_ids, this callback function is used to check + * whether input (-T <image_type>) is supported by registered image + * generation/list low level code + */ + int (*check_image_type) (uint8_t); + /* This callback function will be executed if fflag is defined */ + int (*fflag_handle) (struct image_tool_params *); + /* + * This callback function will be executed for variable size record + * It is expected to build this header in memory and return its length + * and a pointer to it by using image_type_params.header_size and + * image_type_params.hdr. The return value shall indicate if an + * additional padding should be used when copying the data image + * by returning the padding length. + */ + int (*vrec_header) (struct image_tool_params *, + struct image_type_params *); + /* pointer to the next registered entry in linked list */ + struct image_type_params *next; +}; + +/* + * Tool registration function. + */ +typedef void (*imagetool_register_t)(struct image_type_params *); + +/* + * Initializes all image types with the given registration callback + * function. + * An image tool uses this function to initialize all image types. + */ +void register_image_tool(imagetool_register_t image_register); + +/* + * Register a image type within a tool. + * An image type uses this function to register itself within + * all tools. + */ +void register_image_type(struct image_type_params *tparams); + +/* + * There is a c file associated with supported image type low level code + * for ex. default_image.c, fit_image.c + * init_xxx_type() is the only function referred by image tool core to avoid + * a single lined header file, you can define them here + * + * Supported image types init functions + */ +void init_default_image_type(void); +void init_pbl_image_type(void); +void init_ais_image_type(void); +void init_kwb_image_type(void); +void init_imx_image_type(void); +void init_mxs_image_type(void); +void init_fit_image_type(void); +void init_ubl_image_type(void); +void init_omap_image_type(void); +void init_gpimage_type(void); + +void pbl_load_uboot(int fd, struct image_tool_params *mparams); + +#endif /* _IMAGETOOL_H_ */ diff --git a/qemu/roms/u-boot/tools/img2brec.sh b/qemu/roms/u-boot/tools/img2brec.sh new file mode 100755 index 000000000..0fcdba27d --- /dev/null +++ b/qemu/roms/u-boot/tools/img2brec.sh @@ -0,0 +1,388 @@ +#!/bin/sh + +# This script converts binary files (u-boot.bin) into so called +# bootstrap records that are accepted by Motorola's MC9328MX1/L +# (a.k.a. DragaonBall i.MX) in "Bootstrap Mode" +# +# The code for the SynchFlash programming routines is taken from +# Bootloader\Bin\SyncFlash\programBoot_b.txt contained in +# Motorolas LINUX_BSP_0_3_8.tar.gz +# +# The script could easily extended for AMD flash routines. +# +# 2004-06-23 - steven.scholz@imc-berlin.de + +################################################################################# +# From the posting to the U-Boot-Users mailing list, 23 Jun 2004: +# =============================================================== +# I just hacked a simple script that converts u-boot.bin into a text file +# containg processor init code, SynchFlash programming code and U-Boot data in +# form of so called b-records. +# +# This can be used to programm U-Boot into (Synch)Flash using the Bootstrap +# Mode of the MC9328MX1/L +# +# 0AFE1F3410202E2E2E000000002073756363656564/ +# 0AFE1F44102E0A0000206661696C656420210A0000/ +# 0AFE100000 +# ... +# MX1ADS Sync-flash Programming Utility v0.5 2002/08/21 +# +# Source address (stored in 0x0AFE0000): 0x0A000000 +# Target address (stored in 0x0AFE0004): 0x0C000000 +# Size (stored in 0x0AFE0008): 0x0001A320 +# +# Press any key to start programming ... +# Erasing ... +# Blank checking ... +# Programming ... +# Verifying flash ... succeed. +# +# Programming finished. +# +# So no need for a BDI2000 anymore... ;-) +# +# This is working on my MX1ADS eval board. Hope this could be useful for +# someone. +################################################################################# + +if [ "$#" -lt 1 -o "$#" -gt 2 ] ; then + echo "Usage: $0 infile [outfile]" >&2 + echo " $0 u-boot.bin [u-boot.brec]" >&2 + exit 1 +fi + +if [ "$#" -ge 1 ] ; then + INFILE=$1 +fi + +if [ ! -f $INFILE ] ; then + echo "Error: file '$INFILE' does not exist." >&2 + exit 1 +fi + +FILESIZE=`filesize $INFILE` + +output_init() +{ +echo "\ +********************************************
+* Initialize I/O Pad Driving Strength *
+********************************************
+0021B80CC4000003AB
+********************************************
+* Initialize SDRAM *
+********************************************
+00221000C492120200 ; pre-charge command
+08200000E4 ; special read
+
+00221000C4A2120200 ; auto-refresh command
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+
+00221000C4B2120200 ; set mode register
+08111800E4 ; special read
+
+00221000C482124200 ; set normal mode
+
" +} + +output_uboot() +{ +echo "\ +********************************************
+* U-Boot image as bootstrap records *
+* will be stored in SDRAM at 0x0A000000 *
+********************************************
+
" + +cat $INFILE | \ +hexdump -v -e "\"0A0%05.5_ax10\" 16/1 \"%02x\"\"\r\n\"" | \ +tr [:lower:] [:upper:] +} + +output_flashprog() +{ +echo "\ +********************************************
+* Address of arguments to flashProg *
+* ---------------------------------------- *
+* Source : 0x0A000000 *
+* Destination : 0x0C000000 *
" + +# get the real size of the U-Boot image +printf "* Size : 0x%08X *\r\n" $FILESIZE +printf "********************************************\r\n" +printf "0AFE0000CC0A0000000C000000%08X\r\n" $FILESIZE + +#;0AFE0000CC0A0000000C00000000006000
+ +echo "\ +********************************************
+* Flash Program *
+********************************************
+0AFE10001008D09FE5AC0000EA00F0A0E1A42DFE0A
+0AFE1010100080FE0A0DC0A0E100D82DE904B04CE2
+0AFE1020109820A0E318309FE5003093E5033082E0
+0AFE103010003093E5013003E2FF3003E20300A0E1
+0AFE10401000A81BE9A01DFE0A0DC0A0E100D82DE9
+0AFE10501004B04CE204D04DE20030A0E10D304BE5
+0AFE1060109820A0E330309FE5003093E5033082E0
+0AFE107010003093E5013903E2000053E3F7FFFF0A
+0AFE1080104020A0E310309FE5003093E5032082E0
+0AFE1090100D305BE5003082E500A81BE9A01DFE0A
+0AFE10A0100DC0A0E100D82DE904B04CE20000A0E1
+0AFE10B010D7FFFFEB0030A0E1FF3003E2000053E3
+0AFE10C010FAFFFF0A10309FE5003093E5003093E5
+0AFE10D010FF3003E20300A0E100A81BE9A01DFE0A
+0AFE10E0100DC0A0E100D82DE904B04CE204D04DE2
+0AFE10F0100030A0E10D304BE50D305BE52332A0E1
+0AFE1100100E304BE50E305BE5090053E30300009A
+0AFE1110100E305BE5373083E20E304BE5020000EA
+0AFE1120100E305BE5303083E20E304BE50E305BE5
+0AFE1130100300A0E1C3FFFFEB0D305BE50F3003E2
+0AFE1140100E304BE50E305BE5090053E30300009A
+0AFE1150100E305BE5373083E20E304BE5020000EA
+0AFE1160100E305BE5303083E20E304BE50E305BE5
+0AFE1170100300A0E1B3FFFFEB00A81BE90DC0A0E1
+0AFE11801000D82DE904B04CE21CD04DE210000BE5
+0AFE11901014100BE518200BE588009FE5E50200EB
+0AFE11A01010301BE51C300BE514301BE520300BE5
+0AFE11B0100030A0E324300BE524201BE518301BE5
+0AFE11C010030052E10000003A120000EA1C004BE2
+0AFE11D010002090E520104BE2003091E500C093E5
+0AFE11E010043083E2003081E5003092E5042082E2
+0AFE11F010002080E50C0053E10200000A0030A0E3
+0AFE12001028300BE5050000EA24301BE5043083E2
+0AFE12101024300BE5E7FFFFEA0130A0E328300BE5
+0AFE12201028001BE500A81BE9E81EFE0A0DC0A0E1
+0AFE12301000D82DE904B04CE214D04DE210000BE5
+0AFE12401014100BE56C009FE5BA0200EB10301BE5
+0AFE12501018300BE50030A0E31C300BE51C201BE5
+0AFE12601014301BE5030052E10000003A0D0000EA
+0AFE12701018304BE2002093E5001092E5042082E2
+0AFE128010002083E5010071E30200000A0030A0E3
+0AFE12901020300BE5050000EA1C301BE5043083E2
+0AFE12A0101C300BE5ECFFFFEA0130A0E320300BE5
+0AFE12B01020001BE500A81BE9001FFE0A0DC0A0E1
+0AFE12C01000D82DE904B04CE224D04DE20130A0E3
+0AFE12D01024300BE5A4229FE58139A0E3023A83E2
+0AFE12E010003082E59820A0E390329FE5003093E5
+0AFE12F010033082E0003093E5023903E2000053E3
+0AFE1300100300001A74229FE58139A0E3033A83E2
+0AFE131010003082E568029FE5860200EBAF36A0E3
+0AFE1320100E3883E2003093E510300BE554029FE5
+0AFE133010800200EB10301BE5233CA0E1FF3003E2
+0AFE1340100300A0E165FFFFEB10301BE52338A0E1
+0AFE135010FF3003E20300A0E160FFFFEB10301BE5
+0AFE1360102334A0E1FF3003E20300A0E15BFFFFEB
+0AFE13701010305BE50300A0E158FFFFEB0A00A0E3
+0AFE13801030FFFFEB0D00A0E32EFFFFEBAF36A0E3
+0AFE1390100E3883E2043083E2003093E514300BE5
+0AFE13A010E4019FE5630200EB14301BE5233CA0E1
+0AFE13B010FF3003E20300A0E148FFFFEB14301BE5
+0AFE13C0102338A0E1FF3003E20300A0E143FFFFEB
+0AFE13D01014301BE52334A0E1FF3003E20300A0E1
+0AFE13E0103EFFFFEB14305BE50300A0E13BFFFFEB
+0AFE13F0100A00A0E313FFFFEB0D00A0E311FFFFEB
+0AFE140010AF36A0E30E3883E2083083E2003093E5
+0AFE14101018300BE574019FE5460200EB18301BE5
+0AFE142010233CA0E1FF3003E20300A0E12BFFFFEB
+0AFE14301018301BE52338A0E1FF3003E20300A0E1
+0AFE14401026FFFFEB18301BE52334A0E1FF3003E2
+0AFE1450100300A0E121FFFFEB18305BE50300A0E1
+0AFE1460101EFFFFEB0A00A0E3F6FEFFEB0D00A0E3
+0AFE147010F4FEFFEBE6FEFFEB0030A0E1FF3003E2
+0AFE148010000053E30000001A020000EA03FFFFEB
+0AFE1490102D004BE5F6FFFFEAF4009FE5250200EB
+0AFE14A010FEFEFFEB2D004BE5CD0000EBC00000EB
+0AFE14B010E0009FE51F0200EB18301BE528300BE5
+0AFE14C01014301BE52C300BE52C001BE5100100EB
+0AFE14D01028301BE5013643E228300BE52C301BE5
+0AFE14E010013683E22C300BE528301BE5000053E3
+0AFE14F010F4FFFFCAAE0000EB14001BE518101BE5
+0AFE15001049FFFFEB0030A0E1FF3003E2000053E3
+0AFE151010E6FFFF0A80009FE5060200EB10001BE5
+0AFE15201014101BE518201BE5D00000EB10001BE5
+0AFE15301014101BE518201BE50FFFFFEB0030A0E1
+0AFE154010FF3003E2000053E30200000A4C009FE5
+0AFE155010F80100EB010000EA44009FE5F50100EB
+0AFE156010930000EB3C009FE5F20100EB0000A0E3
+0AFE157010A4FEFFEB0030A0E30300A0E100A81BE9
+0AFE158010A01DFE0AA41DFE0AE01DFE0A0C1EFE0A
+0AFE159010381EFE0A641EFE0A181FFE0A281FFE0A
+0AFE15A0103C1FFE0A481FFE0AB41EFE0A0DC0A0E1
+0AFE15B01000D82DE904B04CE204D04DE210000BE5
+0AFE15C01010301BE5013043E210300BE5010073E3
+0AFE15D010FAFFFF1A00A81BE90DC0A0E100D82DE9
+0AFE15E01004B04CE208D04DE210000BE510301BE5
+0AFE15F01014300BE514301BE50300A0E100A81BE9
+0AFE1600100DC0A0E100D82DE904B04CE204D04DE2
+0AFE1610102228A0E3012A82E2042082E2E134A0E3
+0AFE162010023883E2033C83E2003082E50333A0E3
+0AFE163010053983E2003093E510300BE500A81BE9
+0AFE1640100DC0A0E100D82DE904B04CE204D04DE2
+0AFE1650102228A0E3012A82E2042082E29134A0E3
+0AFE166010023883E2033C83E2003082E5C136A0E3
+0AFE167010003093E510300BE52228A0E3012A82E2
+0AFE168010042082E2E134A0E3023883E2033C83E2
+0AFE169010003082E50333A0E3073983E20020A0E3
+0AFE16A010002083E52228A0E3012A82E2042082E2
+0AFE16B0108134A0E3023883E2033C83E2003082E5
+0AFE16C0100333A0E3003093E510300BE5CBFFFFEB
+0AFE16D01010301BE50300A0E100A81BE90DC0A0E1
+0AFE16E01000D82DE904B04CE208D04DE2D3FFFFEB
+0AFE16F0100030A0E110300BE510301BE5023503E2
+0AFE170010000053E30500000A10301BE5073703E2
+0AFE171010000053E30100000A10001BE5ADFFFFEB
+0AFE17201010301BE5803003E2000053E30500000A
+0AFE17301010301BE51C3003E2000053E30100000A
+0AFE17401010001BE5A3FFFFEB10201BE50235A0E3
+0AFE175010803083E2030052E10200001A0130A0E3
+0AFE17601014300BE5010000EA0030A0E314300BE5
+0AFE17701014001BE500A81BE90DC0A0E100D82DE9
+0AFE17801004B04CE204D04DE22228A0E3012A82E2
+0AFE179010042082E29134A0E3023883E2033C83E2
+0AFE17A010003082E5C136A0E3003093E510300BE5
+0AFE17B01000A81BE90DC0A0E100D82DE904B04CE2
+0AFE17C010ECFFFFEB2228A0E3012A82E2042082E2
+0AFE17D0108134A0E3023883E2033C83E2003082E5
+0AFE17E01000A81BE90DC0A0E100D82DE904B04CE2
+0AFE17F01004D04DE22228A0E3012A82E2042082E2
+0AFE1800102238A0E3013A83E2043083E2003093E5
+0AFE181010023183E3003082E52228A0E3012A82E2
+0AFE1820102238A0E3013A83E2003093E5023183E3
+0AFE183010003082E5FA0FA0E35BFFFFEB2228A0E3
+0AFE184010012A82E2042082E2B134A0E3023883E2
+0AFE185010033C83E2003082E50333A0E3233983E2
+0AFE186010033B83E2003093E510300BE500A81BE9
+0AFE1870100DC0A0E100D82DE904B04CE21CD04DE2
+0AFE18801010000BE514100BE518200BE50030A0E3
+0AFE1890101C300BE51C201BE518301BE5030052E1
+0AFE18A0100000003A190000EAB2FFFFEB2228A0E3
+0AFE18B010012A82E2042082E2F134A0E3023883E2
+0AFE18C010033C83E2003082E514201BE51C301BE5
+0AFE18D010031082E010201BE51C301BE5033082E0
+0AFE18E010003093E5003081E57BFFFFEB0030A0E1
+0AFE18F010FF3003E2000053E3FAFFFF0AACFFFFEB
+0AFE1900101C301BE5043083E21C300BE5E0FFFFEA
+0AFE19101000A81BE90DC0A0E100D82DE904B04CE2
+0AFE1920100CD04DE210000BE52228A0E3012A82E2
+0AFE193010042082E28134A0E3023883E2033C83E2
+0AFE194010003082E510301BE5003093E514300BE5
+0AFE1950102228A0E3012A82E2042082E29134A0E3
+0AFE196010023883E2033C83E2003082E510301BE5
+0AFE197010003093E518300BE52228A0E3012A82E2
+0AFE198010042082E2E134A0E3023883E2033C83E2
+0AFE199010003082E50229A0E310301BE5032082E0
+0AFE19A0100030A0E3003082E52228A0E3012A82E2
+0AFE19B010042082E28134A0E3023883E2033C83E2
+0AFE19C010003082E510201BE50D3AA0E3D03083E2
+0AFE19D010033883E1003082E53FFFFFEB0030A0E1
+0AFE19E010FF3003E2000053E3FAFFFF0A70FFFFEB
+0AFE19F01000A81BE90DC0A0E100D82DE904B04CE2
+0AFE1A00105CFFFFEB2228A0E3012A82E2042082E2
+0AFE1A1010E134A0E3023883E2033C83E2003082E5
+0AFE1A20100333A0E3033983E20020A0E3002083E5
+0AFE1A30102228A0E3012A82E2042082E28134A0E3
+0AFE1A4010023883E2033C83E2003082E50323A0E3
+0AFE1A5010032982E20339A0E3C03083E2033883E1
+0AFE1A6010003082E500A81BE90DC0A0E100D82DE9
+0AFE1A701004B04CE23FFFFFEB2228A0E3012A82E2
+0AFE1A8010042082E2E134A0E3023883E2033C83E2
+0AFE1A9010003082E50333A0E30A3983E20020A0E3
+0AFE1AA010002083E52228A0E3012A82E2042082E2
+0AFE1AB0108134A0E3023883E2033C83E2003082E5
+0AFE1AC0100323A0E30A2982E20339A0E3C03083E2
+0AFE1AD010033883E1003082E500A81BE90DC0A0E1
+0AFE1AE01000D82DE904B04CE28729A0E3222E82E2
+0AFE1AF0108739A0E3223E83E2003093E51E3CC3E3
+0AFE1B0010003082E58729A0E38E2F82E28739A0E3
+0AFE1B10108E3F83E2003093E51E3CC3E3003082E5
+0AFE1B20108139A0E3823D83E20520A0E3002083E5
+0AFE1B30108129A0E3822D82E2042082E20139A0E3
+0AFE1B4010273083E2003082E58139A0E3823D83E2
+0AFE1B50100C3083E20120A0E3002083E58129A0E3
+0AFE1B6010822D82E2102082E22A3DA0E3013083E2
+0AFE1B7010003082E58139A0E3823D83E2243083E2
+0AFE1B80100F20A0E3002083E58139A0E3823D83E2
+0AFE1B9010283083E28A20A0E3002083E58139A0E3
+0AFE1BA010823D83E22C3083E20820A0E3002083E5
+0AFE1BB01000A81BE90DC0A0E100D82DE904B04CE2
+0AFE1BC0108139A0E3823D83E2183083E2003093E5
+0AFE1BD010013003E2FF3003E20300A0E100A81BE9
+0AFE1BE0100DC0A0E100D82DE904B04CE204D04DE2
+0AFE1BF0100030A0E10D304BE58139A0E3823D83E2
+0AFE1C0010183083E2003093E5013903E2000053E3
+0AFE1C1010F8FFFF0A8139A0E3813D83E20D205BE5
+0AFE1C2010002083E50D305BE50A0053E30A00001A
+0AFE1C30108139A0E3823D83E2183083E2003093E5
+0AFE1C4010013903E2000053E3F8FFFF0A8139A0E3
+0AFE1C5010813D83E20D20A0E3002083E500A81BE9
+0AFE1C60100DC0A0E100D82DE904B04CE20000A0E1
+0AFE1C7010CFFFFFEB0030A0E1FF3003E2000053E3
+0AFE1C8010FAFFFF0A8139A0E3023A83E2003093E5
+0AFE1C9010FF3003E20300A0E100A81BE90DC0A0E1
+0AFE1CA01000D82DE904B04CE204D04DE20030A0E1
+0AFE1CB0100D304BE50D305BE52332A0E10E304BE5
+0AFE1CC0100E305BE5090053E30300009A0E305BE5
+0AFE1CD010373083E20E304BE5020000EA0E305BE5
+0AFE1CE010303083E20E304BE50E305BE50300A0E1
+0AFE1CF010BAFFFFEB0D305BE50F3003E20E304BE5
+0AFE1D00100E305BE5090053E30300009A0E305BE5
+0AFE1D1010373083E20E304BE5020000EA0E305BE5
+0AFE1D2010303083E20E304BE50E305BE50300A0E1
+0AFE1D3010AAFFFFEB00A81BE90DC0A0E100D82DE9
+0AFE1D401004B04CE204D04DE210000BE510301BE5
+0AFE1D50100030D3E5000053E30000001A080000EA
+0AFE1D601010104BE2003091E50320A0E10020D2E5
+0AFE1D7010013083E2003081E50200A0E197FFFFEB
+0AFE1D8008F1FFFFEA00A81BE9
+0AFE1DA4100A0D4D58314144532053796E632D666C
+0AFE1DB4106173682050726F6772616D6D696E6720
+0AFE1DC4105574696C6974792076302E3520323030
+0AFE1DD410322F30382F32310A0D000000536F7572
+0AFE1DE41063652061646472657373202873746F72
+0AFE1DF410656420696E2030783041464530303030
+0AFE1E0410293A2030780000005461726765742061
+0AFE1E1410646472657373202873746F7265642069
+0AFE1E24106E2030783041464530303034293A2030
+0AFE1E34107800000053697A652020202020202020
+0AFE1E44102020202873746F72656420696E203078
+0AFE1E54103041464530303038293A203078000000
+0AFE1E6410507265737320616E79206B657920746F
+0AFE1E74102073746172742070726F6772616D6D69
+0AFE1E84106E67202E2E2E00000A0D45726173696E
+0AFE1E94106720666C617368202E2E2E000A0D5072
+0AFE1EA4106F6772616D6D696E67202E2E2E000000
+0AFE1EB4100A0D50726F6772616D6D696E67206669
+0AFE1EC4106E69736865642E0A0D50726573732027
+0AFE1ED410612720746F20636F6E74696E7565202E
+0AFE1EE4102E2E2E000A0D566572696679696E6720
+0AFE1EF410666C617368202E2E2E0000000A0D426C
+0AFE1F0410616E6B20636865636B696E67202E2E2E
+0AFE1F1410000000000A45726173696E67202E2E2E
+0AFE1F2410000000000A50726F6772616D6D696E67
+0AFE1F3410202E2E2E000000002073756363656564
+0AFE1F44102E0A0000206661696C656420210A0000
+0AFE100000
+
" +} + +######################################################### + +if [ "$#" -eq 2 ] ; then + output_init > $2 + output_uboot >> $2 + output_flashprog >> $2 +else + output_init; + output_uboot; + output_flashprog; +fi diff --git a/qemu/roms/u-boot/tools/img2srec.c b/qemu/roms/u-boot/tools/img2srec.c new file mode 100644 index 000000000..ec7696402 --- /dev/null +++ b/qemu/roms/u-boot/tools/img2srec.c @@ -0,0 +1,372 @@ +/************************************************************************* +| COPYRIGHT (c) 2000 BY ABATRON AG +|************************************************************************* +| +| PROJECT NAME: Linux Image to S-record Conversion Utility +| FILENAME : img2srec.c +| +| COMPILER : GCC +| +| TARGET OS : LINUX / UNIX +| TARGET HW : - +| +| PROGRAMMER : Abatron / RD +| CREATION : 07.07.00 +| +|************************************************************************* +| +| DESCRIPTION : +| +| Utility to convert a Linux Boot Image to S-record: +| ================================================== +| +| This command line utility can be used to convert a Linux boot image +| (zimage.initrd) to S-Record format used for flash programming. +| This conversion takes care of the special sections "IMAGE" and INITRD". +| +| img2srec [-o offset] image > image.srec +| +| +| Build the utility: +| ================== +| +| To build the utility use GCC as follows: +| +| gcc img2srec.c -o img2srec +| +| +|************************************************************************* +| +| +| UPDATES : +| +| DATE NAME CHANGES +| ----------------------------------------------------------- +| Latest update +| +| 07.07.00 aba Initial release +| +|*************************************************************************/ + +/************************************************************************* +| INCLUDES +|*************************************************************************/ + +#include "os_support.h" +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <elf.h> +#include <unistd.h> +#include <errno.h> + +/************************************************************************* +| FUNCTIONS +|*************************************************************************/ + +static char* ExtractHex (uint32_t* value, char* getPtr) +{ + uint32_t num; + uint32_t digit; + uint8_t c; + + while (*getPtr == ' ') getPtr++; + num = 0; + for (;;) { + c = *getPtr; + if ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0'); + else if ((c >= 'A') && (c <= 'F')) digit = (uint32_t)(c - 'A' + 10); + else if ((c >= 'a') && (c <= 'f')) digit = (uint32_t)(c - 'a' + 10); + else break; + num <<= 4; + num += digit; + getPtr++; + } /* for */ + *value = num; + return getPtr; +} /* ExtractHex */ + +static char* ExtractDecimal (uint32_t* value, char* getPtr) +{ + uint32_t num; + uint32_t digit; + uint8_t c; + + while (*getPtr == ' ') getPtr++; + num = 0; + for (;;) { + c = *getPtr; + if ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0'); + else break; + num *= 10; + num += digit; + getPtr++; + } /* for */ + *value = num; + return getPtr; +} /* ExtractDecimal */ + + +static void ExtractNumber (uint32_t* value, char* getPtr) +{ + bool neg = false;; + + while (*getPtr == ' ') getPtr++; + if (*getPtr == '-') { + neg = true; + getPtr++; + } /* if */ + if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) { + getPtr +=2; + (void)ExtractHex(value, getPtr); + } /* if */ + else { + (void)ExtractDecimal(value, getPtr); + } /* else */ + if (neg) *value = -(*value); +} /* ExtractNumber */ + + +static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer) +{ + uint16_t x; + x = (uint16_t)*buffer++; + x = (x<<8) + (uint16_t)*buffer++; + *value = x; + return buffer; +} /* ExtractWord */ + + +static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer) +{ + uint32_t x; + x = (uint32_t)*buffer++; + x = (x<<8) + (uint32_t)*buffer++; + x = (x<<8) + (uint32_t)*buffer++; + x = (x<<8) + (uint32_t)*buffer++; + *value = x; + return buffer; +} /* ExtractLong */ + + +static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer) +{ + while (count--) *data++ = *buffer++; + return buffer; +} /* ExtractBlock */ + + +static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum) +{ + uint16_t temp; + + static char ByteToHex[] = "0123456789ABCDEF"; + + *pCheckSum += value; + temp = value / 16; + *pa++ = ByteToHex[temp]; + temp = value % 16; + *pa++ = ByteToHex[temp]; + return pa; +} + + +static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr, + const uint8_t* data, int nCount) +{ + uint16_t addrLen; + uint16_t sRLen; + uint16_t checkSum; + uint16_t i; + + switch (sType) { + case 0: + case 1: + case 9: + addrLen = 2; + break; + case 2: + case 8: + addrLen = 3; + break; + case 3: + case 7: + addrLen = 4; + break; + default: + return pa; + } /* switch */ + + *pa++ = 'S'; + *pa++ = (char)(sType + '0'); + sRLen = addrLen + nCount + 1; + checkSum = 0; + pa = WriteHex(pa, (uint8_t)sRLen, &checkSum); + + /* Write address field */ + for (i = 1; i <= addrLen; i++) { + pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum); + } /* for */ + + /* Write code/data fields */ + for (i = 0; i < nCount; i++) { + pa = WriteHex(pa, *data++, &checkSum); + } /* for */ + + /* Write checksum field */ + checkSum = ~checkSum; + pa = WriteHex(pa, (uint8_t)checkSum, &checkSum); + *pa++ = '\0'; + return pa; +} + + +static void ConvertELF(char* fileName, uint32_t loadOffset) +{ + FILE* file; + int i; + int rxCount; + uint8_t rxBlock[1024]; + uint32_t loadSize; + uint32_t firstAddr; + uint32_t loadAddr; + uint32_t loadDiff = 0; + Elf32_Ehdr elfHeader; + Elf32_Shdr sectHeader[32]; + uint8_t* getPtr; + char srecLine[128]; + char *hdr_name; + + + /* open file */ + if ((file = fopen(fileName,"rb")) == NULL) { + fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno)); + return; + } /* if */ + + /* read ELF header */ + rxCount = fread(rxBlock, 1, sizeof elfHeader, file); + getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock); + getPtr = ExtractWord(&elfHeader.e_type, getPtr); + getPtr = ExtractWord(&elfHeader.e_machine, getPtr); + getPtr = ExtractLong((uint32_t *)&elfHeader.e_version, getPtr); + getPtr = ExtractLong((uint32_t *)&elfHeader.e_entry, getPtr); + getPtr = ExtractLong((uint32_t *)&elfHeader.e_phoff, getPtr); + getPtr = ExtractLong((uint32_t *)&elfHeader.e_shoff, getPtr); + getPtr = ExtractLong((uint32_t *)&elfHeader.e_flags, getPtr); + getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr); + getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr); + getPtr = ExtractWord(&elfHeader.e_phnum, getPtr); + getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr); + getPtr = ExtractWord(&elfHeader.e_shnum, getPtr); + getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr); + if ( (rxCount != sizeof elfHeader) + || (elfHeader.e_ident[0] != ELFMAG0) + || (elfHeader.e_ident[1] != ELFMAG1) + || (elfHeader.e_ident[2] != ELFMAG2) + || (elfHeader.e_ident[3] != ELFMAG3) + || (elfHeader.e_type != ET_EXEC) + ) { + fclose(file); + fprintf (stderr, "*** illegal file format\n"); + return; + } /* if */ + + /* read all section headers */ + fseek(file, elfHeader.e_shoff, SEEK_SET); + for (i = 0; i < elfHeader.e_shnum; i++) { + rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_name, rxBlock); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_type, getPtr); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_flags, getPtr); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_addr, getPtr); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_offset, getPtr); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_size, getPtr); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_link, getPtr); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_info, getPtr); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_addralign, getPtr); + getPtr = ExtractLong((uint32_t *)§Header[i].sh_entsize, getPtr); + if (rxCount != sizeof sectHeader[0]) { + fclose(file); + fprintf (stderr, "*** illegal file format\n"); + return; + } /* if */ + } /* for */ + + if ((hdr_name = strrchr(fileName, '/')) == NULL) { + hdr_name = fileName; + } else { + ++hdr_name; + } + /* write start record */ + (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name)); + printf("%s\r\n",srecLine); + + /* write data records */ + firstAddr = ~0; + loadAddr = 0; + for (i = 0; i < elfHeader.e_shnum; i++) { + if ( (sectHeader[i].sh_type == SHT_PROGBITS) + && (sectHeader[i].sh_size != 0) + ) { + loadSize = sectHeader[i].sh_size; + if (sectHeader[i].sh_flags != 0) { + loadAddr = sectHeader[i].sh_addr; + loadDiff = loadAddr - sectHeader[i].sh_offset; + } /* if */ + else { + loadAddr = sectHeader[i].sh_offset + loadDiff; + } /* else */ + + if (loadAddr < firstAddr) + firstAddr = loadAddr; + + /* build s-records */ + loadSize = sectHeader[i].sh_size; + fseek(file, sectHeader[i].sh_offset, SEEK_SET); + while (loadSize) { + rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file); + if (rxCount < 0) { + fclose(file); + fprintf (stderr, "*** illegal file format\n"); + return; + } /* if */ + (void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount); + loadSize -= rxCount; + loadAddr += rxCount; + printf("%s\r\n",srecLine); + } /* while */ + } /* if */ + } /* for */ + + /* add end record */ + (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0); + printf("%s\r\n",srecLine); + fclose(file); +} /* ConvertELF */ + + +/************************************************************************* +| MAIN +|*************************************************************************/ + +int main( int argc, char *argv[ ]) +{ + uint32_t offset; + + if (argc == 2) { + ConvertELF(argv[1], 0); + } /* if */ + else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) { + ExtractNumber(&offset, argv[2]); + ConvertELF(argv[3], offset); + } /* if */ + else { + fprintf (stderr, "Usage: img2srec [-o offset] <image>\n"); + } /* if */ + + return 0; +} /* main */ diff --git a/qemu/roms/u-boot/tools/imximage.c b/qemu/roms/u-boot/tools/imximage.c new file mode 100644 index 000000000..18dc051c5 --- /dev/null +++ b/qemu/roms/u-boot/tools/imximage.c @@ -0,0 +1,705 @@ +/* + * (C) Copyright 2009 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * (C) Copyright 2008 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include <image.h> +#include "imximage.h" + +#define UNDEFINED 0xFFFFFFFF + +/* + * Supported commands for configuration file + */ +static table_entry_t imximage_cmds[] = { + {CMD_BOOT_FROM, "BOOT_FROM", "boot command", }, + {CMD_BOOT_OFFSET, "BOOT_OFFSET", "Boot offset", }, + {CMD_DATA, "DATA", "Reg Write Data", }, + {CMD_CSF, "CSF", "Command Sequence File", }, + {CMD_IMAGE_VERSION, "IMAGE_VERSION", "image version", }, + {-1, "", "", }, +}; + +/* + * Supported Boot options for configuration file + * this is needed to set the correct flash offset + */ +static table_entry_t imximage_boot_offset[] = { + {FLASH_OFFSET_ONENAND, "onenand", "OneNAND Flash",}, + {FLASH_OFFSET_NAND, "nand", "NAND Flash", }, + {FLASH_OFFSET_NOR, "nor", "NOR Flash", }, + {FLASH_OFFSET_SATA, "sata", "SATA Disk", }, + {FLASH_OFFSET_SD, "sd", "SD Card", }, + {FLASH_OFFSET_SPI, "spi", "SPI Flash", }, + {-1, "", "Invalid", }, +}; + +/* + * Supported Boot options for configuration file + * this is needed to determine the initial load size + */ +static table_entry_t imximage_boot_loadsize[] = { + {FLASH_LOADSIZE_ONENAND, "onenand", "OneNAND Flash",}, + {FLASH_LOADSIZE_NAND, "nand", "NAND Flash", }, + {FLASH_LOADSIZE_NOR, "nor", "NOR Flash", }, + {FLASH_LOADSIZE_SATA, "sata", "SATA Disk", }, + {FLASH_LOADSIZE_SD, "sd", "SD Card", }, + {FLASH_LOADSIZE_SPI, "spi", "SPI Flash", }, + {-1, "", "Invalid", }, +}; + +/* + * IMXIMAGE version definition for i.MX chips + */ +static table_entry_t imximage_versions[] = { + {IMXIMAGE_V1, "", " (i.MX25/35/51 compatible)", }, + {IMXIMAGE_V2, "", " (i.MX53/6 compatible)", }, + {-1, "", " (Invalid)", }, +}; + +static struct imx_header imximage_header; +static uint32_t imximage_version; +/* + * Image Vector Table Offset + * Initialized to a wrong not 4-bytes aligned address to + * check if it is was set by the cfg file. + */ +static uint32_t imximage_ivt_offset = UNDEFINED; +static uint32_t imximage_csf_size = UNDEFINED; +/* Initial Load Region Size */ +static uint32_t imximage_init_loadsize; + +static set_dcd_val_t set_dcd_val; +static set_dcd_rst_t set_dcd_rst; +static set_imx_hdr_t set_imx_hdr; +static uint32_t max_dcd_entries; +static uint32_t *header_size_ptr; +static uint32_t *csf_ptr; + +static uint32_t get_cfg_value(char *token, char *name, int linenr) +{ + char *endptr; + uint32_t value; + + errno = 0; + value = strtoul(token, &endptr, 16); + if (errno || (token == endptr)) { + fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", + name, linenr, token); + exit(EXIT_FAILURE); + } + return value; +} + +static uint32_t detect_imximage_version(struct imx_header *imx_hdr) +{ + imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; + imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; + flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; + flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; + + /* Try to detect V1 */ + if ((fhdr_v1->app_code_barker == APP_CODE_BARKER) && + (hdr_v1->dcd_table.preamble.barker == DCD_BARKER)) + return IMXIMAGE_V1; + + /* Try to detect V2 */ + if ((fhdr_v2->header.tag == IVT_HEADER_TAG) && + (hdr_v2->dcd_table.header.tag == DCD_HEADER_TAG)) + return IMXIMAGE_V2; + + return IMXIMAGE_VER_INVALID; +} + +static void err_imximage_version(int version) +{ + fprintf(stderr, + "Error: Unsupported imximage version:%d\n", version); + + exit(EXIT_FAILURE); +} + +static void set_dcd_val_v1(struct imx_header *imxhdr, char *name, int lineno, + int fld, uint32_t value, uint32_t off) +{ + dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; + + switch (fld) { + case CFG_REG_SIZE: + /* Byte, halfword, word */ + if ((value != 1) && (value != 2) && (value != 4)) { + fprintf(stderr, "Error: %s[%d] - " + "Invalid register size " "(%d)\n", + name, lineno, value); + exit(EXIT_FAILURE); + } + dcd_v1->addr_data[off].type = value; + break; + case CFG_REG_ADDRESS: + dcd_v1->addr_data[off].addr = value; + break; + case CFG_REG_VALUE: + dcd_v1->addr_data[off].value = value; + break; + default: + break; + + } +} + +static void set_dcd_val_v2(struct imx_header *imxhdr, char *name, int lineno, + int fld, uint32_t value, uint32_t off) +{ + dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; + + switch (fld) { + case CFG_REG_ADDRESS: + dcd_v2->addr_data[off].addr = cpu_to_be32(value); + break; + case CFG_REG_VALUE: + dcd_v2->addr_data[off].value = cpu_to_be32(value); + break; + default: + break; + + } +} + +/* + * Complete setting up the rest field of DCD of V1 + * such as barker code and DCD data length. + */ +static void set_dcd_rst_v1(struct imx_header *imxhdr, uint32_t dcd_len, + char *name, int lineno) +{ + dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; + + dcd_v1->preamble.barker = DCD_BARKER; + dcd_v1->preamble.length = dcd_len * sizeof(dcd_type_addr_data_t); +} + +/* + * Complete setting up the reset field of DCD of V2 + * such as DCD tag, version, length, etc. + */ +static void set_dcd_rst_v2(struct imx_header *imxhdr, uint32_t dcd_len, + char *name, int lineno) +{ + dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; + + dcd_v2->header.tag = DCD_HEADER_TAG; + dcd_v2->header.length = cpu_to_be16( + dcd_len * sizeof(dcd_addr_data_t) + 8); + dcd_v2->header.version = DCD_VERSION; + dcd_v2->write_dcd_command.tag = DCD_COMMAND_TAG; + dcd_v2->write_dcd_command.length = cpu_to_be16( + dcd_len * sizeof(dcd_addr_data_t) + 4); + dcd_v2->write_dcd_command.param = DCD_COMMAND_PARAM; +} + +static void set_imx_hdr_v1(struct imx_header *imxhdr, uint32_t dcd_len, + uint32_t entry_point, uint32_t flash_offset) +{ + imx_header_v1_t *hdr_v1 = &imxhdr->header.hdr_v1; + flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; + dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; + uint32_t hdr_base; + uint32_t header_length = (((char *)&dcd_v1->addr_data[dcd_len].addr) + - ((char *)imxhdr)); + + /* Set magic number */ + fhdr_v1->app_code_barker = APP_CODE_BARKER; + + /* TODO: check i.MX image V1 handling, for now use 'old' style */ + hdr_base = entry_point - 4096; + fhdr_v1->app_dest_ptr = hdr_base - flash_offset; + fhdr_v1->app_code_jump_vector = entry_point; + + fhdr_v1->dcd_ptr_ptr = hdr_base + offsetof(flash_header_v1_t, dcd_ptr); + fhdr_v1->dcd_ptr = hdr_base + offsetof(imx_header_v1_t, dcd_table); + + /* Security feature are not supported */ + fhdr_v1->app_code_csf = 0; + fhdr_v1->super_root_key = 0; + header_size_ptr = (uint32_t *)(((char *)imxhdr) + header_length - 4); +} + +static void set_imx_hdr_v2(struct imx_header *imxhdr, uint32_t dcd_len, + uint32_t entry_point, uint32_t flash_offset) +{ + imx_header_v2_t *hdr_v2 = &imxhdr->header.hdr_v2; + flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; + uint32_t hdr_base; + + /* Set magic number */ + fhdr_v2->header.tag = IVT_HEADER_TAG; /* 0xD1 */ + fhdr_v2->header.length = cpu_to_be16(sizeof(flash_header_v2_t)); + fhdr_v2->header.version = IVT_VERSION; /* 0x40 */ + + fhdr_v2->entry = entry_point; + fhdr_v2->reserved1 = fhdr_v2->reserved2 = 0; + hdr_base = entry_point - imximage_init_loadsize + + flash_offset; + fhdr_v2->self = hdr_base; + fhdr_v2->dcd_ptr = hdr_base + offsetof(imx_header_v2_t, dcd_table); + fhdr_v2->boot_data_ptr = hdr_base + + offsetof(imx_header_v2_t, boot_data); + hdr_v2->boot_data.start = entry_point - imximage_init_loadsize; + + fhdr_v2->csf = 0; + + header_size_ptr = &hdr_v2->boot_data.size; + csf_ptr = &fhdr_v2->csf; +} + +static void set_hdr_func(void) +{ + switch (imximage_version) { + case IMXIMAGE_V1: + set_dcd_val = set_dcd_val_v1; + set_dcd_rst = set_dcd_rst_v1; + set_imx_hdr = set_imx_hdr_v1; + max_dcd_entries = MAX_HW_CFG_SIZE_V1; + break; + case IMXIMAGE_V2: + set_dcd_val = set_dcd_val_v2; + set_dcd_rst = set_dcd_rst_v2; + set_imx_hdr = set_imx_hdr_v2; + max_dcd_entries = MAX_HW_CFG_SIZE_V2; + break; + default: + err_imximage_version(imximage_version); + break; + } +} + +static void print_hdr_v1(struct imx_header *imx_hdr) +{ + imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; + flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; + dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; + uint32_t size, length, ver; + + size = dcd_v1->preamble.length; + if (size > (MAX_HW_CFG_SIZE_V1 * sizeof(dcd_type_addr_data_t))) { + fprintf(stderr, + "Error: Image corrupt DCD size %d exceed maximum %d\n", + (uint32_t)(size / sizeof(dcd_type_addr_data_t)), + MAX_HW_CFG_SIZE_V1); + exit(EXIT_FAILURE); + } + + length = dcd_v1->preamble.length / sizeof(dcd_type_addr_data_t); + ver = detect_imximage_version(imx_hdr); + + printf("Image Type: Freescale IMX Boot Image\n"); + printf("Image Ver: %x", ver); + printf("%s\n", get_table_entry_name(imximage_versions, NULL, ver)); + printf("Data Size: "); + genimg_print_size(dcd_v1->addr_data[length].type); + printf("Load Address: %08x\n", (uint32_t)fhdr_v1->app_dest_ptr); + printf("Entry Point: %08x\n", (uint32_t)fhdr_v1->app_code_jump_vector); +} + +static void print_hdr_v2(struct imx_header *imx_hdr) +{ + imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; + flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; + dcd_v2_t *dcd_v2 = &hdr_v2->dcd_table; + uint32_t size, version; + + size = be16_to_cpu(dcd_v2->header.length) - 8; + if (size > (MAX_HW_CFG_SIZE_V2 * sizeof(dcd_addr_data_t))) { + fprintf(stderr, + "Error: Image corrupt DCD size %d exceed maximum %d\n", + (uint32_t)(size / sizeof(dcd_addr_data_t)), + MAX_HW_CFG_SIZE_V2); + exit(EXIT_FAILURE); + } + + version = detect_imximage_version(imx_hdr); + + printf("Image Type: Freescale IMX Boot Image\n"); + printf("Image Ver: %x", version); + printf("%s\n", get_table_entry_name(imximage_versions, NULL, version)); + printf("Data Size: "); + genimg_print_size(hdr_v2->boot_data.size); + printf("Load Address: %08x\n", (uint32_t)fhdr_v2->boot_data_ptr); + printf("Entry Point: %08x\n", (uint32_t)fhdr_v2->entry); + if (fhdr_v2->csf && (imximage_ivt_offset != UNDEFINED) && + (imximage_csf_size != UNDEFINED)) { + printf("HAB Blocks: %08x %08x %08x\n", + (uint32_t)fhdr_v2->self, 0, + hdr_v2->boot_data.size - imximage_ivt_offset - + imximage_csf_size); + } +} + +static void parse_cfg_cmd(struct imx_header *imxhdr, int32_t cmd, char *token, + char *name, int lineno, int fld, int dcd_len) +{ + int value; + static int cmd_ver_first = ~0; + + switch (cmd) { + case CMD_IMAGE_VERSION: + imximage_version = get_cfg_value(token, name, lineno); + if (cmd_ver_first == 0) { + fprintf(stderr, "Error: %s[%d] - IMAGE_VERSION " + "command need be the first before other " + "valid command in the file\n", name, lineno); + exit(EXIT_FAILURE); + } + cmd_ver_first = 1; + set_hdr_func(); + break; + case CMD_BOOT_FROM: + imximage_ivt_offset = get_table_entry_id(imximage_boot_offset, + "imximage boot option", token); + if (imximage_ivt_offset == -1) { + fprintf(stderr, "Error: %s[%d] -Invalid boot device" + "(%s)\n", name, lineno, token); + exit(EXIT_FAILURE); + } + + imximage_init_loadsize = + get_table_entry_id(imximage_boot_loadsize, + "imximage boot option", token); + + if (imximage_init_loadsize == -1) { + fprintf(stderr, + "Error: %s[%d] -Invalid boot device(%s)\n", + name, lineno, token); + exit(EXIT_FAILURE); + } + + /* + * The SOC loads from the storage starting at address 0 + * then ensures that the load size contains the offset + */ + if (imximage_init_loadsize < imximage_ivt_offset) + imximage_init_loadsize = imximage_ivt_offset; + if (unlikely(cmd_ver_first != 1)) + cmd_ver_first = 0; + break; + case CMD_BOOT_OFFSET: + imximage_ivt_offset = get_cfg_value(token, name, lineno); + if (unlikely(cmd_ver_first != 1)) + cmd_ver_first = 0; + break; + case CMD_DATA: + value = get_cfg_value(token, name, lineno); + (*set_dcd_val)(imxhdr, name, lineno, fld, value, dcd_len); + if (unlikely(cmd_ver_first != 1)) + cmd_ver_first = 0; + break; + case CMD_CSF: + if (imximage_version != 2) { + fprintf(stderr, + "Error: %s[%d] - CSF only supported for VERSION 2(%s)\n", + name, lineno, token); + exit(EXIT_FAILURE); + } + imximage_csf_size = get_cfg_value(token, name, lineno); + if (unlikely(cmd_ver_first != 1)) + cmd_ver_first = 0; + break; + } +} + +static void parse_cfg_fld(struct imx_header *imxhdr, int32_t *cmd, + char *token, char *name, int lineno, int fld, int *dcd_len) +{ + int value; + + switch (fld) { + case CFG_COMMAND: + *cmd = get_table_entry_id(imximage_cmds, + "imximage commands", token); + if (*cmd < 0) { + fprintf(stderr, "Error: %s[%d] - Invalid command" + "(%s)\n", name, lineno, token); + exit(EXIT_FAILURE); + } + break; + case CFG_REG_SIZE: + parse_cfg_cmd(imxhdr, *cmd, token, name, lineno, fld, *dcd_len); + break; + case CFG_REG_ADDRESS: + case CFG_REG_VALUE: + if (*cmd != CMD_DATA) + return; + + value = get_cfg_value(token, name, lineno); + (*set_dcd_val)(imxhdr, name, lineno, fld, value, *dcd_len); + + if (fld == CFG_REG_VALUE) { + (*dcd_len)++; + if (*dcd_len > max_dcd_entries) { + fprintf(stderr, "Error: %s[%d] -" + "DCD table exceeds maximum size(%d)\n", + name, lineno, max_dcd_entries); + exit(EXIT_FAILURE); + } + } + break; + default: + break; + } +} +static uint32_t parse_cfg_file(struct imx_header *imxhdr, char *name) +{ + FILE *fd = NULL; + char *line = NULL; + char *token, *saveptr1, *saveptr2; + int lineno = 0; + int fld; + size_t len; + int dcd_len = 0; + int32_t cmd; + + fd = fopen(name, "r"); + if (fd == 0) { + fprintf(stderr, "Error: %s - Can't open DCD file\n", name); + exit(EXIT_FAILURE); + } + + /* + * Very simple parsing, line starting with # are comments + * and are dropped + */ + while ((getline(&line, &len, fd)) > 0) { + lineno++; + + token = strtok_r(line, "\r\n", &saveptr1); + if (token == NULL) + continue; + + /* Check inside the single line */ + for (fld = CFG_COMMAND, cmd = CMD_INVALID, + line = token; ; line = NULL, fld++) { + token = strtok_r(line, " \t", &saveptr2); + if (token == NULL) + break; + + /* Drop all text starting with '#' as comments */ + if (token[0] == '#') + break; + + parse_cfg_fld(imxhdr, &cmd, token, name, + lineno, fld, &dcd_len); + } + + } + + (*set_dcd_rst)(imxhdr, dcd_len, name, lineno); + fclose(fd); + + /* Exit if there is no BOOT_FROM field specifying the flash_offset */ + if (imximage_ivt_offset == FLASH_OFFSET_UNDEFINED) { + fprintf(stderr, "Error: No BOOT_FROM tag in %s\n", name); + exit(EXIT_FAILURE); + } + return dcd_len; +} + + +static int imximage_check_image_types(uint8_t type) +{ + if (type == IH_TYPE_IMXIMAGE) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +} + +static int imximage_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + struct imx_header *imx_hdr = (struct imx_header *) ptr; + + if (detect_imximage_version(imx_hdr) == IMXIMAGE_VER_INVALID) + return -FDT_ERR_BADSTRUCTURE; + + return 0; +} + +static void imximage_print_header(const void *ptr) +{ + struct imx_header *imx_hdr = (struct imx_header *) ptr; + uint32_t version = detect_imximage_version(imx_hdr); + + switch (version) { + case IMXIMAGE_V1: + print_hdr_v1(imx_hdr); + break; + case IMXIMAGE_V2: + print_hdr_v2(imx_hdr); + break; + default: + err_imximage_version(version); + break; + } +} + +static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + struct imx_header *imxhdr = (struct imx_header *)ptr; + uint32_t dcd_len; + + /* + * In order to not change the old imx cfg file + * by adding VERSION command into it, here need + * set up function ptr group to V1 by default. + */ + imximage_version = IMXIMAGE_V1; + /* Be able to detect if the cfg file has no BOOT_FROM tag */ + imximage_ivt_offset = FLASH_OFFSET_UNDEFINED; + imximage_csf_size = 0; + set_hdr_func(); + + /* Parse dcd configuration file */ + dcd_len = parse_cfg_file(imxhdr, params->imagename); + + /* Set the imx header */ + (*set_imx_hdr)(imxhdr, dcd_len, params->ep, imximage_ivt_offset); + + /* + * ROM bug alert + * + * MX53 only loads 512 byte multiples in case of SD boot. + * MX53 only loads NAND page multiples in case of NAND boot and + * supports up to 4096 byte large pages, thus align to 4096. + * + * The remaining fraction of a block bytes would not be loaded! + */ + *header_size_ptr = ROUND(sbuf->st_size, 4096); + + if (csf_ptr && imximage_csf_size) { + *csf_ptr = params->ep - imximage_init_loadsize + + *header_size_ptr; + *header_size_ptr += imximage_csf_size; + } +} + +int imximage_check_params(struct image_tool_params *params) +{ + if (!params) + return CFG_INVALID; + if (!strlen(params->imagename)) { + fprintf(stderr, "Error: %s - Configuration file not specified, " + "it is needed for imximage generation\n", + params->cmdname); + return CFG_INVALID; + } + /* + * Check parameters: + * XIP is not allowed and verify that incompatible + * parameters are not sent at the same time + * For example, if list is required a data image must not be provided + */ + return (params->dflag && (params->fflag || params->lflag)) || + (params->fflag && (params->dflag || params->lflag)) || + (params->lflag && (params->dflag || params->fflag)) || + (params->xflag) || !(strlen(params->imagename)); +} + +static int imximage_generate(struct image_tool_params *params, + struct image_type_params *tparams) +{ + struct imx_header *imxhdr; + size_t alloc_len; + struct stat sbuf; + char *datafile = params->datafile; + uint32_t pad_len; + + memset(&imximage_header, 0, sizeof(imximage_header)); + + /* + * In order to not change the old imx cfg file + * by adding VERSION command into it, here need + * set up function ptr group to V1 by default. + */ + imximage_version = IMXIMAGE_V1; + /* Be able to detect if the cfg file has no BOOT_FROM tag */ + imximage_ivt_offset = FLASH_OFFSET_UNDEFINED; + imximage_csf_size = 0; + set_hdr_func(); + + /* Parse dcd configuration file */ + parse_cfg_file(&imximage_header, params->imagename); + + /* TODO: check i.MX image V1 handling, for now use 'old' style */ + if (imximage_version == IMXIMAGE_V1) { + alloc_len = 4096; + } else { + if (imximage_init_loadsize < imximage_ivt_offset + + sizeof(imx_header_v2_t)) + imximage_init_loadsize = imximage_ivt_offset + + sizeof(imx_header_v2_t); + alloc_len = imximage_init_loadsize - imximage_ivt_offset; + } + + if (alloc_len < sizeof(struct imx_header)) { + fprintf(stderr, "%s: header error\n", + params->cmdname); + exit(EXIT_FAILURE); + } + + imxhdr = malloc(alloc_len); + + if (!imxhdr) { + fprintf(stderr, "%s: malloc return failure: %s\n", + params->cmdname, strerror(errno)); + exit(EXIT_FAILURE); + } + + memset(imxhdr, 0, alloc_len); + + tparams->header_size = alloc_len; + tparams->hdr = imxhdr; + + /* determine data image file length */ + + if (stat(datafile, &sbuf) < 0) { + fprintf(stderr, "%s: Can't stat %s: %s\n", + params->cmdname, datafile, strerror(errno)); + exit(EXIT_FAILURE); + } + + pad_len = ROUND(sbuf.st_size, 4096) - sbuf.st_size; + + /* TODO: check i.MX image V1 handling, for now use 'old' style */ + if (imximage_version == IMXIMAGE_V1) + return 0; + else + return pad_len; +} + + +/* + * imximage parameters + */ +static struct image_type_params imximage_params = { + .name = "Freescale i.MX Boot Image support", + .header_size = 0, + .hdr = NULL, + .check_image_type = imximage_check_image_types, + .verify_header = imximage_verify_header, + .print_header = imximage_print_header, + .set_header = imximage_set_header, + .check_params = imximage_check_params, + .vrec_header = imximage_generate, +}; + +void init_imx_image_type(void) +{ + register_image_type(&imximage_params); +} diff --git a/qemu/roms/u-boot/tools/imximage.h b/qemu/roms/u-boot/tools/imximage.h new file mode 100644 index 000000000..01f861e7a --- /dev/null +++ b/qemu/roms/u-boot/tools/imximage.h @@ -0,0 +1,175 @@ +/* + * (C) Copyright 2009 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _IMXIMAGE_H_ +#define _IMXIMAGE_H_ + +#define MAX_HW_CFG_SIZE_V2 121 /* Max number of registers imx can set for v2 */ +#define MAX_HW_CFG_SIZE_V1 60 /* Max number of registers imx can set for v1 */ +#define APP_CODE_BARKER 0xB1 +#define DCD_BARKER 0xB17219E9 + +/* + * NOTE: This file must be kept in sync with arch/arm/include/asm/\ + * imx-common/imximage.cfg because tools/imximage.c can not + * cross-include headers from arch/arm/ and vice-versa. + */ +#define CMD_DATA_STR "DATA" + +/* Initial Vector Table Offset */ +#define FLASH_OFFSET_UNDEFINED 0xFFFFFFFF +#define FLASH_OFFSET_STANDARD 0x400 +#define FLASH_OFFSET_NAND FLASH_OFFSET_STANDARD +#define FLASH_OFFSET_SD FLASH_OFFSET_STANDARD +#define FLASH_OFFSET_SPI FLASH_OFFSET_STANDARD +#define FLASH_OFFSET_ONENAND 0x100 +#define FLASH_OFFSET_NOR 0x1000 +#define FLASH_OFFSET_SATA FLASH_OFFSET_STANDARD + +/* Initial Load Region Size */ +#define FLASH_LOADSIZE_UNDEFINED 0xFFFFFFFF +#define FLASH_LOADSIZE_STANDARD 0x1000 +#define FLASH_LOADSIZE_NAND FLASH_LOADSIZE_STANDARD +#define FLASH_LOADSIZE_SD FLASH_LOADSIZE_STANDARD +#define FLASH_LOADSIZE_SPI FLASH_LOADSIZE_STANDARD +#define FLASH_LOADSIZE_ONENAND 0x400 +#define FLASH_LOADSIZE_NOR 0x0 /* entire image */ +#define FLASH_LOADSIZE_SATA FLASH_LOADSIZE_STANDARD + +#define IVT_HEADER_TAG 0xD1 +#define IVT_VERSION 0x40 +#define DCD_HEADER_TAG 0xD2 +#define DCD_COMMAND_TAG 0xCC +#define DCD_VERSION 0x40 +#define DCD_COMMAND_PARAM 0x4 + +enum imximage_cmd { + CMD_INVALID, + CMD_IMAGE_VERSION, + CMD_BOOT_FROM, + CMD_BOOT_OFFSET, + CMD_DATA, + CMD_CSF, +}; + +enum imximage_fld_types { + CFG_INVALID = -1, + CFG_COMMAND, + CFG_REG_SIZE, + CFG_REG_ADDRESS, + CFG_REG_VALUE +}; + +enum imximage_version { + IMXIMAGE_VER_INVALID = -1, + IMXIMAGE_V1 = 1, + IMXIMAGE_V2 +}; + +typedef struct { + uint32_t type; /* Type of pointer (byte, halfword, word, wait/read) */ + uint32_t addr; /* Address to write to */ + uint32_t value; /* Data to write */ +} dcd_type_addr_data_t; + +typedef struct { + uint32_t barker; /* Barker for sanity check */ + uint32_t length; /* Device configuration length (without preamble) */ +} dcd_preamble_t; + +typedef struct { + dcd_preamble_t preamble; + dcd_type_addr_data_t addr_data[MAX_HW_CFG_SIZE_V1]; +} dcd_v1_t; + +typedef struct { + uint32_t app_code_jump_vector; + uint32_t app_code_barker; + uint32_t app_code_csf; + uint32_t dcd_ptr_ptr; + uint32_t super_root_key; + uint32_t dcd_ptr; + uint32_t app_dest_ptr; +} flash_header_v1_t; + +typedef struct { + uint32_t length; /* Length of data to be read from flash */ +} flash_cfg_parms_t; + +typedef struct { + flash_header_v1_t fhdr; + dcd_v1_t dcd_table; + flash_cfg_parms_t ext_header; +} imx_header_v1_t; + +typedef struct { + uint32_t addr; + uint32_t value; +} dcd_addr_data_t; + +typedef struct { + uint8_t tag; + uint16_t length; + uint8_t version; +} __attribute__((packed)) ivt_header_t; + +typedef struct { + uint8_t tag; + uint16_t length; + uint8_t param; +} __attribute__((packed)) write_dcd_command_t; + +typedef struct { + ivt_header_t header; + write_dcd_command_t write_dcd_command; + dcd_addr_data_t addr_data[MAX_HW_CFG_SIZE_V2]; +} dcd_v2_t; + +typedef struct { + uint32_t start; + uint32_t size; + uint32_t plugin; +} boot_data_t; + +typedef struct { + ivt_header_t header; + uint32_t entry; + uint32_t reserved1; + uint32_t dcd_ptr; + uint32_t boot_data_ptr; + uint32_t self; + uint32_t csf; + uint32_t reserved2; +} flash_header_v2_t; + +typedef struct { + flash_header_v2_t fhdr; + boot_data_t boot_data; + dcd_v2_t dcd_table; +} imx_header_v2_t; + +/* The header must be aligned to 4k on MX53 for NAND boot */ +struct imx_header { + union { + imx_header_v1_t hdr_v1; + imx_header_v2_t hdr_v2; + } header; +}; + +typedef void (*set_dcd_val_t)(struct imx_header *imxhdr, + char *name, int lineno, + int fld, uint32_t value, + uint32_t off); + +typedef void (*set_dcd_rst_t)(struct imx_header *imxhdr, + uint32_t dcd_len, + char *name, int lineno); + +typedef void (*set_imx_hdr_t)(struct imx_header *imxhdr, uint32_t dcd_len, + uint32_t entry_point, uint32_t flash_offset); + +#endif /* _IMXIMAGE_H_ */ diff --git a/qemu/roms/u-boot/tools/jtagconsole b/qemu/roms/u-boot/tools/jtagconsole new file mode 100755 index 000000000..d404fac5e --- /dev/null +++ b/qemu/roms/u-boot/tools/jtagconsole @@ -0,0 +1,39 @@ +#!/bin/sh + +usage() { + ( + echo "Usage: $0 [board IP] [board port]" + echo "" + echo "If IP is not specified, 'localhost' will be used" + echo "If port is not specified, '2001' will be used" + [ -z "$*" ] && exit 0 + echo "" + echo "ERROR: $*" + exit 1 + ) 1>&2 + exit $? +} + +while [ -n "$1" ] ; do + case $1 in + -h|--help) usage;; + --) break;; + -*) usage "Invalid option $1";; + *) break;; + esac + shift +done + +ip=${1:-localhost} +port=${2:-2001} + +if [ -z "${ip}" ] || [ -n "$3" ] ; then + usage "Invalid number of arguments" +fi + +trap "stty icanon echo opost intr ^C" 0 2 3 5 10 13 15 +echo "NOTE: the interrupt signal (normally ^C) has been remapped to ^T" + +stty -icanon -echo -opost intr ^T +nc ${ip} ${port} +exit 0 diff --git a/qemu/roms/u-boot/tools/kermit/README b/qemu/roms/u-boot/tools/kermit/README new file mode 100644 index 000000000..c3b491aa5 --- /dev/null +++ b/qemu/roms/u-boot/tools/kermit/README @@ -0,0 +1,51 @@ +# +# (C) Copyright 2001 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +This directory contains scripts that help to perform certain actions +that need to be done frequently when working with U-Boot. + +They are meant as EXAMPLE code, so it is very likely that you will +have to modify them before use. + + +Short description: +================== + +dot.kermrc: + + Example for "~/.kermrc" Kermit init file for use with U-Boot + + by Wolfgang Denk, 24 Jun 2001 + +flash_param: + + "kermit" script to automatically initialize the environment + variables on your target. This is most useful during + development when your environment variables are stored in an + embedded flash sector which is erased whenever you install a + new U-Boot image. + + by Swen Anderson, 10 May 2001 + +send_cmd: + + send_cmd U_BOOT_COMMAND + + "kermit" script to send a U-Boot command and print the + results. When used from a shell with history (like the bash) + this indirectly adds kind of history to U-Boot ;-) + + by Swen Anderson, 10 May 2001 + +send_image: + + send_image FILE_NAME OFFSET + + "kermit" script to automatically download a file to the + target using the "loadb" command (kermit binary protocol) + + by Swen Anderson, 10 May 2001 diff --git a/qemu/roms/u-boot/tools/kermit/dot.kermrc b/qemu/roms/u-boot/tools/kermit/dot.kermrc new file mode 100644 index 000000000..0fc6c15d3 --- /dev/null +++ b/qemu/roms/u-boot/tools/kermit/dot.kermrc @@ -0,0 +1,16 @@ +set line /dev/ttyS0 +set speed 115200 +set carrier-watch off +set handshake none +set flow-control none +robust +set file type bin +set file name lit +set rec pack 1000 +set send pack 1000 +set window 5 +set prompt Kermit> +define sz !sz \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line) +define rz !rz \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line) +define sx !sx \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line) +define rx !rx \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line) diff --git a/qemu/roms/u-boot/tools/kermit/flash_param b/qemu/roms/u-boot/tools/kermit/flash_param new file mode 100644 index 000000000..847f99e1e --- /dev/null +++ b/qemu/roms/u-boot/tools/kermit/flash_param @@ -0,0 +1,60 @@ +#!/usr/bin/kermit + +# usage: ./flash_param parameters +# Parameters: IP Address ETH Address ERIC Number +# Format: xxx.xxx.xxx.xxx xx:xx:xx:xx:xx:xx xxxx + +set line /dev/ttyS0 +set speed 115200 +set serial 8N1 +set carrier-watch off +set handshake none +#set flow-control none +set flow-control xon/xoff +#robust +set file type bin +set file name lit +set rec pack 1000 +set send pack 1000 +set window 5 +set prompt Kermit> +#robust +# Milliseconds to pause between each OUTPUT character +set output pacing 1 + +out \13 +in 10 => +#first erase the environment memory within NVRAM +out mw f0000000 0 200\13 +in 10 => +out reset\13 +in 5 autoboot +out \13\13 +in 10 => +#set additional env parameter +out setenv ethaddr \%2\13 +in 10 => +out setenv serial# ERIC 1.0 \%3\13 +in 10 => +out setenv eric_id \%3\13 +in 10 => +#out setenv prec_videocard_bus unknown\13 +#in 10 => +#out setenv prec_bios_type unknown\13 +#in 10 => +out setenv eric_passwd .eRIC.\13 +in 10 => +#out setenv bootargs root=/dev/ram ramdisk_size=8192 init=/sbin/init ip=\%1:192.168.1.100:192.168.1.254:255.255.255.0\13 +#out setenv bootargs root=/dev/ram ramdisk_size=8192 init=/sbin/init ip=\%1:192.168.0.1\13 +#out setenv bootargs root=/dev/ram ramdisk_size=8192 init=/sbin/init ip=\%1\13 +out setenv bootargs console=/dev/ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.26:/eric_root_devel ip=\%1:192.168.1.26\13 +in 10 => +out setenv bootcmd bootm FFC00000\13 +in 10 => +out saveenv\13 +in 10 => +out reset\13 +in 5 autoboot +out \13\13 +in 10 => +quit +exit 0 diff --git a/qemu/roms/u-boot/tools/kermit/send_cmd b/qemu/roms/u-boot/tools/kermit/send_cmd new file mode 100644 index 000000000..4131331f0 --- /dev/null +++ b/qemu/roms/u-boot/tools/kermit/send_cmd @@ -0,0 +1,21 @@ +#!/usr/bin/kermit + +set line /dev/ttyS0 +set speed 115200 +set serial 8N1 +set carrier-watch off +set handshake none +set flow-control none +robust +set file type bin +set file name lit +set rec pack 1000 +set send pack 1000 +set window 5 +set prompt Kermit> + +#out \13 +#in 10 => +out \%1 \%2 \%3 \%4 \%5 \%6 \%7\13 +in 10 => +quit +exit 0 diff --git a/qemu/roms/u-boot/tools/kermit/send_image b/qemu/roms/u-boot/tools/kermit/send_image new file mode 100644 index 000000000..9b89d6b05 --- /dev/null +++ b/qemu/roms/u-boot/tools/kermit/send_image @@ -0,0 +1,26 @@ +#!/usr/bin/kermit + +# usage: send_image FILE_NAME OFFSET +# e.g. send_image output.bin 1F00000 +set line /dev/ttyS0 +set speed 115200 +set serial 8N1 +set carrier-watch off +set handshake none +set flow-control none +robust +set file type bin +set file name lit +set rec pack 1000 +set send pack 1000 +set window 5 +set prompt Kermit> + +out \13 +in 10 => +out loadb \%2 \13 +in 10 download ... +send \%1 +out \13 +in 10 ## Start Addr +quit +exit 0 diff --git a/qemu/roms/u-boot/tools/kwbimage.c b/qemu/roms/u-boot/tools/kwbimage.c new file mode 100644 index 000000000..109d61686 --- /dev/null +++ b/qemu/roms/u-boot/tools/kwbimage.c @@ -0,0 +1,386 @@ +/* + * (C) Copyright 2008 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include <image.h> +#include "kwbimage.h" + +/* + * Supported commands for configuration file + */ +static table_entry_t kwbimage_cmds[] = { + {CMD_BOOT_FROM, "BOOT_FROM", "boot command", }, + {CMD_NAND_ECC_MODE, "NAND_ECC_MODE", "NAND mode", }, + {CMD_NAND_PAGE_SIZE, "NAND_PAGE_SIZE", "NAND size", }, + {CMD_SATA_PIO_MODE, "SATA_PIO_MODE", "SATA mode", }, + {CMD_DDR_INIT_DELAY, "DDR_INIT_DELAY", "DDR init dly", }, + {CMD_DATA, "DATA", "Reg Write Data", }, + {CMD_INVALID, "", "", }, +}; + +/* + * Supported Boot options for configuration file + */ +static table_entry_t kwbimage_bootops[] = { + {IBR_HDR_SPI_ID, "spi", "SPI Flash", }, + {IBR_HDR_NAND_ID, "nand", "NAND Flash", }, + {IBR_HDR_SATA_ID, "sata", "Sata port", }, + {IBR_HDR_PEX_ID, "pex", "PCIe port", }, + {IBR_HDR_UART_ID, "uart", "Serial port", }, + {-1, "", "Invalid", }, +}; + +/* + * Supported NAND ecc options configuration file + */ +static table_entry_t kwbimage_eccmodes[] = { + {IBR_HDR_ECC_DEFAULT, "default", "Default mode", }, + {IBR_HDR_ECC_FORCED_HAMMING, "hamming", "Hamming mode", }, + {IBR_HDR_ECC_FORCED_RS, "rs", "RS mode", }, + {IBR_HDR_ECC_DISABLED, "disabled", "ECC Disabled", }, + {-1, "", "", }, +}; + +static struct kwb_header kwbimage_header; +static int datacmd_cnt = 0; +static char * fname = "Unknown"; +static int lineno = -1; + +/* + * Report Error if xflag is set in addition to default + */ +static int kwbimage_check_params(struct image_tool_params *params) +{ + if (!strlen (params->imagename)) { + printf ("Error:%s - Configuration file not specified, " + "it is needed for kwbimage generation\n", + params->cmdname); + return CFG_INVALID; + } + return ((params->dflag && (params->fflag || params->lflag)) || + (params->fflag && (params->dflag || params->lflag)) || + (params->lflag && (params->dflag || params->fflag)) || + (params->xflag) || !(strlen (params->imagename))); +} + +static uint32_t check_get_hexval (char *token) +{ + uint32_t hexval; + + if (!sscanf (token, "%x", &hexval)) { + printf ("Error:%s[%d] - Invalid hex data(%s)\n", fname, + lineno, token); + exit (EXIT_FAILURE); + } + return hexval; +} + +/* + * Generates 8 bit checksum + */ +static uint8_t kwbimage_checksum8 (void *start, uint32_t len, uint8_t csum) +{ + register uint8_t sum = csum; + volatile uint8_t *p = (volatile uint8_t *)start; + + /* check len and return zero checksum if invalid */ + if (!len) + return 0; + + do { + sum += *p; + p++; + } while (--len); + return (sum); +} + +/* + * Generates 32 bit checksum + */ +static uint32_t kwbimage_checksum32 (uint32_t *start, uint32_t len, uint32_t csum) +{ + register uint32_t sum = csum; + volatile uint32_t *p = start; + + /* check len and return zero checksum if invalid */ + if (!len) + return 0; + + if (len % sizeof(uint32_t)) { + printf ("Error:%s[%d] - length is not in multiple of %zu\n", + __FUNCTION__, len, sizeof(uint32_t)); + return 0; + } + + do { + sum += *p; + p++; + len -= sizeof(uint32_t); + } while (len > 0); + return (sum); +} + +static void kwbimage_check_cfgdata (char *token, enum kwbimage_cmd cmdsw, + struct kwb_header *kwbhdr) +{ + bhr_t *mhdr = &kwbhdr->kwb_hdr; + extbhr_t *exthdr = &kwbhdr->kwb_exthdr; + int i; + + switch (cmdsw) { + case CMD_BOOT_FROM: + i = get_table_entry_id (kwbimage_bootops, + "Kwbimage boot option", token); + + if (i < 0) + goto INVL_DATA; + + mhdr->blockid = i; + printf ("Preparing kirkwood boot image to boot " + "from %s\n", token); + break; + case CMD_NAND_ECC_MODE: + i = get_table_entry_id (kwbimage_eccmodes, + "NAND ecc mode", token); + + if (i < 0) + goto INVL_DATA; + + mhdr->nandeccmode = i; + printf ("Nand ECC mode = %s\n", token); + break; + case CMD_NAND_PAGE_SIZE: + mhdr->nandpagesize = + (uint16_t) check_get_hexval (token); + printf ("Nand page size = 0x%x\n", mhdr->nandpagesize); + break; + case CMD_SATA_PIO_MODE: + mhdr->satapiomode = + (uint8_t) check_get_hexval (token); + printf ("Sata PIO mode = 0x%x\n", + mhdr->satapiomode); + break; + case CMD_DDR_INIT_DELAY: + mhdr->ddrinitdelay = + (uint16_t) check_get_hexval (token); + printf ("DDR init delay = %d msec\n", mhdr->ddrinitdelay); + break; + case CMD_DATA: + exthdr->rcfg[datacmd_cnt].raddr = + check_get_hexval (token); + + break; + case CMD_INVALID: + goto INVL_DATA; + default: + goto INVL_DATA; + } + return; + +INVL_DATA: + printf ("Error:%s[%d] - Invalid data\n", fname, lineno); + exit (EXIT_FAILURE); +} + +/* + * this function sets the kwbimage header by- + * 1. Abstracting input command line arguments data + * 2. parses the kwbimage configuration file and update extebded header data + * 3. calculates header, extended header and image checksums + */ +static void kwdimage_set_ext_header (struct kwb_header *kwbhdr, char* name) { + bhr_t *mhdr = &kwbhdr->kwb_hdr; + extbhr_t *exthdr = &kwbhdr->kwb_exthdr; + FILE *fd = NULL; + int j; + char *line = NULL; + char * token, *saveptr1, *saveptr2; + size_t len = 0; + enum kwbimage_cmd cmd; + + fname = name; + /* set dram register offset */ + exthdr->dramregsoffs = (intptr_t)&exthdr->rcfg - (intptr_t)mhdr; + + if ((fd = fopen (name, "r")) == 0) { + printf ("Error:%s - Can't open\n", fname); + exit (EXIT_FAILURE); + } + + /* Simple kwimage.cfg file parser */ + lineno=0; + while ((getline (&line, &len, fd)) > 0) { + lineno++; + token = strtok_r (line, "\r\n", &saveptr1); + /* drop all lines with zero tokens (= empty lines) */ + if (token == NULL) + continue; + + for (j = 0, cmd = CMD_INVALID, line = token; ; line = NULL) { + token = strtok_r (line, " \t", &saveptr2); + if (token == NULL) + break; + /* Drop all text starting with '#' as comments */ + if (token[0] == '#') + break; + + /* Process rest as valid config command line */ + switch (j) { + case CFG_COMMAND: + cmd = get_table_entry_id (kwbimage_cmds, + "Kwbimage command", token); + + if (cmd == CMD_INVALID) + goto INVL_CMD; + break; + + case CFG_DATA0: + kwbimage_check_cfgdata (token, cmd, kwbhdr); + break; + + case CFG_DATA1: + if (cmd != CMD_DATA) + goto INVL_CMD; + + exthdr->rcfg[datacmd_cnt].rdata = + check_get_hexval (token); + + if (datacmd_cnt > KWBIMAGE_MAX_CONFIG ) { + printf ("Error:%s[%d] - Found more " + "than max(%zd) allowed " + "data configurations\n", + fname, lineno, + KWBIMAGE_MAX_CONFIG); + exit (EXIT_FAILURE); + } else + datacmd_cnt++; + break; + + default: + goto INVL_CMD; + } + j++; + } + } + if (line) + free (line); + + fclose (fd); + return; + +/* + * Invalid Command error reporring + * + * command CMD_DATA needs three strings on a line + * whereas other commands need only two. + * + * if more than two/three (as per command type) are observed, + * then error will be reported + */ +INVL_CMD: + printf ("Error:%s[%d] - Invalid command\n", fname, lineno); + exit (EXIT_FAILURE); +} + +static void kwbimage_set_header (void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + struct kwb_header *hdr = (struct kwb_header *)ptr; + bhr_t *mhdr = &hdr->kwb_hdr; + extbhr_t *exthdr = &hdr->kwb_exthdr; + uint32_t checksum; + int size; + + /* Build and add image checksum header */ + checksum = kwbimage_checksum32 ((uint32_t *)ptr, sbuf->st_size, 0); + + size = write (ifd, &checksum, sizeof(uint32_t)); + if (size != sizeof(uint32_t)) { + printf ("Error:%s - Checksum write %d bytes %s\n", + params->cmdname, size, params->imagefile); + exit (EXIT_FAILURE); + } + + sbuf->st_size += sizeof(uint32_t); + + mhdr->blocksize = sbuf->st_size - sizeof(struct kwb_header); + mhdr->srcaddr = sizeof(struct kwb_header); + mhdr->destaddr= params->addr; + mhdr->execaddr =params->ep; + mhdr->ext = 0x1; /* header extension appended */ + + kwdimage_set_ext_header (hdr, params->imagename); + /* calculate checksums */ + mhdr->checkSum = kwbimage_checksum8 ((void *)mhdr, sizeof(bhr_t), 0); + exthdr->checkSum = kwbimage_checksum8 ((void *)exthdr, + sizeof(extbhr_t), 0); +} + +static int kwbimage_verify_header (unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + struct kwb_header *hdr = (struct kwb_header *)ptr; + bhr_t *mhdr = &hdr->kwb_hdr; + extbhr_t *exthdr = &hdr->kwb_exthdr; + uint8_t calc_hdrcsum; + uint8_t calc_exthdrcsum; + + calc_hdrcsum = kwbimage_checksum8 ((void *)mhdr, + sizeof(bhr_t) - sizeof(uint8_t), 0); + if (calc_hdrcsum != mhdr->checkSum) + return -FDT_ERR_BADSTRUCTURE; /* mhdr csum not matched */ + + calc_exthdrcsum = kwbimage_checksum8 ((void *)exthdr, + sizeof(extbhr_t) - sizeof(uint8_t), 0); + if (calc_exthdrcsum != exthdr->checkSum) + return -FDT_ERR_BADSTRUCTURE; /* exthdr csum not matched */ + + return 0; +} + +static void kwbimage_print_header (const void *ptr) +{ + struct kwb_header *hdr = (struct kwb_header *) ptr; + bhr_t *mhdr = &hdr->kwb_hdr; + char *name = get_table_entry_name (kwbimage_bootops, + "Kwbimage boot option", + (int) mhdr->blockid); + + printf ("Image Type: Kirkwood Boot from %s Image\n", name); + printf ("Data Size: "); + genimg_print_size (mhdr->blocksize - sizeof(uint32_t)); + printf ("Load Address: %08x\n", mhdr->destaddr); + printf ("Entry Point: %08x\n", mhdr->execaddr); +} + +static int kwbimage_check_image_types (uint8_t type) +{ + if (type == IH_TYPE_KWBIMAGE) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +} + +/* + * kwbimage type parameters definition + */ +static struct image_type_params kwbimage_params = { + .name = "Kirkwood Boot Image support", + .header_size = sizeof(struct kwb_header), + .hdr = (void*)&kwbimage_header, + .check_image_type = kwbimage_check_image_types, + .verify_header = kwbimage_verify_header, + .print_header = kwbimage_print_header, + .set_header = kwbimage_set_header, + .check_params = kwbimage_check_params, +}; + +void init_kwb_image_type (void) +{ + register_image_type(&kwbimage_params); +} diff --git a/qemu/roms/u-boot/tools/kwbimage.h b/qemu/roms/u-boot/tools/kwbimage.h new file mode 100644 index 000000000..8e4a4e281 --- /dev/null +++ b/qemu/roms/u-boot/tools/kwbimage.h @@ -0,0 +1,90 @@ +/* + * (C) Copyright 2008 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _KWBIMAGE_H_ +#define _KWBIMAGE_H_ + +#include <stdint.h> + +#define KWBIMAGE_MAX_CONFIG ((0x1dc - 0x20)/sizeof(struct reg_config)) +#define MAX_TEMPBUF_LEN 32 + +/* NAND ECC Mode */ +#define IBR_HDR_ECC_DEFAULT 0x00 +#define IBR_HDR_ECC_FORCED_HAMMING 0x01 +#define IBR_HDR_ECC_FORCED_RS 0x02 +#define IBR_HDR_ECC_DISABLED 0x03 + +/* Boot Type - block ID */ +#define IBR_HDR_I2C_ID 0x4D +#define IBR_HDR_SPI_ID 0x5A +#define IBR_HDR_NAND_ID 0x8B +#define IBR_HDR_SATA_ID 0x78 +#define IBR_HDR_PEX_ID 0x9C +#define IBR_HDR_UART_ID 0x69 +#define IBR_DEF_ATTRIB 0x00 + +enum kwbimage_cmd { + CMD_INVALID, + CMD_BOOT_FROM, + CMD_NAND_ECC_MODE, + CMD_NAND_PAGE_SIZE, + CMD_SATA_PIO_MODE, + CMD_DDR_INIT_DELAY, + CMD_DATA +}; + +enum kwbimage_cmd_types { + CFG_INVALID = -1, + CFG_COMMAND, + CFG_DATA0, + CFG_DATA1 +}; + +/* typedefs */ +typedef struct bhr_t { + uint8_t blockid; /*0 */ + uint8_t nandeccmode; /*1 */ + uint16_t nandpagesize; /*2-3 */ + uint32_t blocksize; /*4-7 */ + uint32_t rsvd1; /*8-11 */ + uint32_t srcaddr; /*12-15 */ + uint32_t destaddr; /*16-19 */ + uint32_t execaddr; /*20-23 */ + uint8_t satapiomode; /*24 */ + uint8_t rsvd3; /*25 */ + uint16_t ddrinitdelay; /*26-27 */ + uint16_t rsvd2; /*28-29 */ + uint8_t ext; /*30 */ + uint8_t checkSum; /*31 */ +} bhr_t, *pbhr_t; + +struct reg_config { + uint32_t raddr; + uint32_t rdata; +}; + +typedef struct extbhr_t { + uint32_t dramregsoffs; + uint8_t rsrvd1[0x20 - sizeof(uint32_t)]; + struct reg_config rcfg[KWBIMAGE_MAX_CONFIG]; + uint8_t rsrvd2[7]; + uint8_t checkSum; +} extbhr_t, *pextbhr_t; + +struct kwb_header { + bhr_t kwb_hdr; + extbhr_t kwb_exthdr; +}; + +/* + * functions + */ +void init_kwb_image_type (void); + +#endif /* _KWBIMAGE_H_ */ diff --git a/qemu/roms/u-boot/tools/kwboot.c b/qemu/roms/u-boot/tools/kwboot.c new file mode 100644 index 000000000..e773f01df --- /dev/null +++ b/qemu/roms/u-boot/tools/kwboot.c @@ -0,0 +1,742 @@ +/* + * Boot a Marvell Kirkwood SoC, with Xmodem over UART0. + * + * (c) 2012 Daniel Stodden <daniel.stodden@gmail.com> + * + * References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281 + * Integrated Controller: Functional Specifications" December 2, + * 2008. Chapter 24.2 "BootROM Firmware". + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <libgen.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <stdint.h> +#include <termios.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include "kwbimage.h" + +#ifdef __GNUC__ +#define PACKED __attribute((packed)) +#else +#define PACKED +#endif + +/* + * Marvell BootROM UART Sensing + */ + +static unsigned char kwboot_msg_boot[] = { + 0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 +}; + +#define KWBOOT_MSG_REQ_DELAY 10 /* ms */ +#define KWBOOT_MSG_RSP_TIMEO 50 /* ms */ + +/* + * Xmodem Transfers + */ + +#define SOH 1 /* sender start of block header */ +#define EOT 4 /* sender end of block transfer */ +#define ACK 6 /* target block ack */ +#define NAK 21 /* target block negative ack */ +#define CAN 24 /* target/sender transfer cancellation */ + +struct kwboot_block { + uint8_t soh; + uint8_t pnum; + uint8_t _pnum; + uint8_t data[128]; + uint8_t csum; +} PACKED; + +#define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */ + +static int kwboot_verbose; + +static void +kwboot_printv(const char *fmt, ...) +{ + va_list ap; + + if (kwboot_verbose) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + fflush(stdout); + } +} + +static void +__spinner(void) +{ + const char seq[] = { '-', '\\', '|', '/' }; + const int div = 8; + static int state, bs; + + if (state % div == 0) { + fputc(bs, stdout); + fputc(seq[state / div % sizeof(seq)], stdout); + fflush(stdout); + } + + bs = '\b'; + state++; +} + +static void +kwboot_spinner(void) +{ + if (kwboot_verbose) + __spinner(); +} + +static void +__progress(int pct, char c) +{ + const int width = 70; + static const char *nl = ""; + static int pos; + + if (pos % width == 0) + printf("%s%3d %% [", nl, pct); + + fputc(c, stdout); + + nl = "]\n"; + pos++; + + if (pct == 100) { + while (pos++ < width) + fputc(' ', stdout); + fputs(nl, stdout); + } + + fflush(stdout); + +} + +static void +kwboot_progress(int _pct, char c) +{ + static int pct; + + if (_pct != -1) + pct = _pct; + + if (kwboot_verbose) + __progress(pct, c); +} + +static int +kwboot_tty_recv(int fd, void *buf, size_t len, int timeo) +{ + int rc, nfds; + fd_set rfds; + struct timeval tv; + ssize_t n; + + rc = -1; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + tv.tv_sec = 0; + tv.tv_usec = timeo * 1000; + if (tv.tv_usec > 1000000) { + tv.tv_sec += tv.tv_usec / 1000000; + tv.tv_usec %= 1000000; + } + + do { + nfds = select(fd + 1, &rfds, NULL, NULL, &tv); + if (nfds < 0) + goto out; + if (!nfds) { + errno = ETIMEDOUT; + goto out; + } + + n = read(fd, buf, len); + if (n < 0) + goto out; + + buf = (char *)buf + n; + len -= n; + } while (len > 0); + + rc = 0; +out: + return rc; +} + +static int +kwboot_tty_send(int fd, const void *buf, size_t len) +{ + int rc; + ssize_t n; + + rc = -1; + + do { + n = write(fd, buf, len); + if (n < 0) + goto out; + + buf = (char *)buf + n; + len -= n; + } while (len > 0); + + rc = tcdrain(fd); +out: + return rc; +} + +static int +kwboot_tty_send_char(int fd, unsigned char c) +{ + return kwboot_tty_send(fd, &c, 1); +} + +static speed_t +kwboot_tty_speed(int baudrate) +{ + switch (baudrate) { + case 115200: + return B115200; + case 57600: + return B57600; + case 38400: + return B38400; + case 19200: + return B19200; + case 9600: + return B9600; + } + + return -1; +} + +static int +kwboot_open_tty(const char *path, speed_t speed) +{ + int rc, fd; + struct termios tio; + + rc = -1; + + fd = open(path, O_RDWR|O_NOCTTY|O_NDELAY); + if (fd < 0) + goto out; + + memset(&tio, 0, sizeof(tio)); + + tio.c_iflag = 0; + tio.c_cflag = CREAD|CLOCAL|CS8; + + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 10; + + cfsetospeed(&tio, speed); + cfsetispeed(&tio, speed); + + rc = tcsetattr(fd, TCSANOW, &tio); + if (rc) + goto out; + + rc = fd; +out: + if (rc < 0) { + if (fd >= 0) + close(fd); + } + + return rc; +} + +static int +kwboot_bootmsg(int tty, void *msg) +{ + int rc; + char c; + + kwboot_printv("Sending boot message. Please reboot the target..."); + + do { + rc = tcflush(tty, TCIOFLUSH); + if (rc) + break; + + rc = kwboot_tty_send(tty, msg, 8); + if (rc) { + usleep(KWBOOT_MSG_REQ_DELAY * 1000); + continue; + } + + rc = kwboot_tty_recv(tty, &c, 1, KWBOOT_MSG_RSP_TIMEO); + + kwboot_spinner(); + + } while (rc || c != NAK); + + kwboot_printv("\n"); + + return rc; +} + +static int +kwboot_xm_makeblock(struct kwboot_block *block, const void *data, + size_t size, int pnum) +{ + const size_t blksz = sizeof(block->data); + size_t n; + int i; + + block->pnum = pnum; + block->_pnum = ~block->pnum; + + n = size < blksz ? size : blksz; + memcpy(&block->data[0], data, n); + memset(&block->data[n], 0, blksz - n); + + block->csum = 0; + for (i = 0; i < n; i++) + block->csum += block->data[i]; + + return n; +} + +static int +kwboot_xm_sendblock(int fd, struct kwboot_block *block) +{ + int rc, retries; + char c; + + retries = 16; + do { + rc = kwboot_tty_send(fd, block, sizeof(*block)); + if (rc) + break; + + rc = kwboot_tty_recv(fd, &c, 1, KWBOOT_BLK_RSP_TIMEO); + if (rc) + break; + + if (c != ACK) + kwboot_progress(-1, '+'); + + } while (c == NAK && retries-- > 0); + + rc = -1; + + switch (c) { + case ACK: + rc = 0; + break; + case NAK: + errno = EBADMSG; + break; + case CAN: + errno = ECANCELED; + break; + default: + errno = EPROTO; + break; + } + + return rc; +} + +static int +kwboot_xmodem(int tty, const void *_data, size_t size) +{ + const uint8_t *data = _data; + int rc, pnum, N, err; + + pnum = 1; + N = 0; + + kwboot_printv("Sending boot image...\n"); + + do { + struct kwboot_block block; + int n; + + n = kwboot_xm_makeblock(&block, + data + N, size - N, + pnum++); + if (n < 0) + goto can; + + if (!n) + break; + + rc = kwboot_xm_sendblock(tty, &block); + if (rc) + goto out; + + N += n; + kwboot_progress(N * 100 / size, '.'); + } while (1); + + rc = kwboot_tty_send_char(tty, EOT); + +out: + return rc; + +can: + err = errno; + kwboot_tty_send_char(tty, CAN); + errno = err; + goto out; +} + +static int +kwboot_term_pipe(int in, int out, char *quit, int *s) +{ + ssize_t nin, nout; + char _buf[128], *buf = _buf; + + nin = read(in, buf, sizeof(buf)); + if (nin < 0) + return -1; + + if (quit) { + int i; + + for (i = 0; i < nin; i++) { + if (*buf == quit[*s]) { + (*s)++; + if (!quit[*s]) + return 0; + buf++; + nin--; + } else + while (*s > 0) { + nout = write(out, quit, *s); + if (nout <= 0) + return -1; + (*s) -= nout; + } + } + } + + while (nin > 0) { + nout = write(out, buf, nin); + if (nout <= 0) + return -1; + nin -= nout; + } + + return 0; +} + +static int +kwboot_terminal(int tty) +{ + int rc, in, s; + char *quit = "\34c"; + struct termios otio, tio; + + rc = -1; + + in = STDIN_FILENO; + if (isatty(in)) { + rc = tcgetattr(in, &otio); + if (!rc) { + tio = otio; + cfmakeraw(&tio); + rc = tcsetattr(in, TCSANOW, &tio); + } + if (rc) { + perror("tcsetattr"); + goto out; + } + + kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n", + quit[0]|0100, quit[1]); + } else + in = -1; + + rc = 0; + s = 0; + + do { + fd_set rfds; + int nfds = 0; + + FD_SET(tty, &rfds); + nfds = nfds < tty ? tty : nfds; + + if (in >= 0) { + FD_SET(in, &rfds); + nfds = nfds < in ? in : nfds; + } + + nfds = select(nfds + 1, &rfds, NULL, NULL, NULL); + if (nfds < 0) + break; + + if (FD_ISSET(tty, &rfds)) { + rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL); + if (rc) + break; + } + + if (FD_ISSET(in, &rfds)) { + rc = kwboot_term_pipe(in, tty, quit, &s); + if (rc) + break; + } + } while (quit[s] != 0); + + tcsetattr(in, TCSANOW, &otio); +out: + return rc; +} + +static void * +kwboot_mmap_image(const char *path, size_t *size, int prot) +{ + int rc, fd, flags; + struct stat st; + void *img; + + rc = -1; + fd = -1; + img = NULL; + + fd = open(path, O_RDONLY); + if (fd < 0) + goto out; + + rc = fstat(fd, &st); + if (rc) + goto out; + + flags = (prot & PROT_WRITE) ? MAP_PRIVATE : MAP_SHARED; + + img = mmap(NULL, st.st_size, prot, flags, fd, 0); + if (img == MAP_FAILED) { + img = NULL; + goto out; + } + + rc = 0; + *size = st.st_size; +out: + if (rc && img) { + munmap(img, st.st_size); + img = NULL; + } + if (fd >= 0) + close(fd); + + return img; +} + +static uint8_t +kwboot_img_csum8(void *_data, size_t size) +{ + uint8_t *data = _data, csum; + + for (csum = 0; size-- > 0; data++) + csum += *data; + + return csum; +} + +static int +kwboot_img_patch_hdr(void *img, size_t size) +{ + int rc; + bhr_t *hdr; + uint8_t csum; + const size_t hdrsz = sizeof(*hdr); + + rc = -1; + hdr = img; + + if (size < hdrsz) { + errno = EINVAL; + goto out; + } + + csum = kwboot_img_csum8(hdr, hdrsz) - hdr->checkSum; + if (csum != hdr->checkSum) { + errno = EINVAL; + goto out; + } + + if (hdr->blockid == IBR_HDR_UART_ID) { + rc = 0; + goto out; + } + + hdr->blockid = IBR_HDR_UART_ID; + + hdr->nandeccmode = IBR_HDR_ECC_DISABLED; + hdr->nandpagesize = 0; + + hdr->srcaddr = hdr->ext + ? sizeof(struct kwb_header) + : sizeof(*hdr); + + hdr->checkSum = kwboot_img_csum8(hdr, hdrsz) - csum; + + rc = 0; +out: + return rc; +} + +static void +kwboot_usage(FILE *stream, char *progname) +{ + fprintf(stream, + "Usage: %s -b <image> [ -p ] [ -t ] " + "[-B <baud> ] <TTY>\n", progname); + fprintf(stream, "\n"); + fprintf(stream, " -b <image>: boot <image>\n"); + fprintf(stream, " -p: patch <image> to type 0x69 (uart boot)\n"); + fprintf(stream, "\n"); + fprintf(stream, " -t: mini terminal\n"); + fprintf(stream, "\n"); + fprintf(stream, " -B <baud>: set baud rate\n"); + fprintf(stream, "\n"); +} + +int +main(int argc, char **argv) +{ + const char *ttypath, *imgpath; + int rv, rc, tty, term, prot, patch; + void *bootmsg; + void *img; + size_t size; + speed_t speed; + + rv = 1; + tty = -1; + bootmsg = NULL; + imgpath = NULL; + img = NULL; + term = 0; + patch = 0; + size = 0; + speed = B115200; + + kwboot_verbose = isatty(STDOUT_FILENO); + + do { + int c = getopt(argc, argv, "hb:ptB:"); + if (c < 0) + break; + + switch (c) { + case 'b': + bootmsg = kwboot_msg_boot; + imgpath = optarg; + break; + + case 'p': + patch = 1; + break; + + case 't': + term = 1; + break; + + case 'B': + speed = kwboot_tty_speed(atoi(optarg)); + if (speed == -1) + goto usage; + break; + + case 'h': + rv = 0; + default: + goto usage; + } + } while (1); + + if (!bootmsg && !term) + goto usage; + + if (patch && !imgpath) + goto usage; + + if (argc - optind < 1) + goto usage; + + ttypath = argv[optind++]; + + tty = kwboot_open_tty(ttypath, speed); + if (tty < 0) { + perror(ttypath); + goto out; + } + + if (imgpath) { + prot = PROT_READ | (patch ? PROT_WRITE : 0); + + img = kwboot_mmap_image(imgpath, &size, prot); + if (!img) { + perror(imgpath); + goto out; + } + } + + if (patch) { + rc = kwboot_img_patch_hdr(img, size); + if (rc) { + fprintf(stderr, "%s: Invalid image.\n", imgpath); + goto out; + } + } + + if (bootmsg) { + rc = kwboot_bootmsg(tty, bootmsg); + if (rc) { + perror("bootmsg"); + goto out; + } + } + + if (img) { + rc = kwboot_xmodem(tty, img, size); + if (rc) { + perror("xmodem"); + goto out; + } + } + + if (term) { + rc = kwboot_terminal(tty); + if (rc && !(errno == EINTR)) { + perror("terminal"); + goto out; + } + } + + rv = 0; +out: + if (tty >= 0) + close(tty); + + if (img) + munmap(img, size); + + return rv; + +usage: + kwboot_usage(rv ? stderr : stdout, basename(argv[0])); + goto out; +} diff --git a/qemu/roms/u-boot/tools/logos/atmel.bmp b/qemu/roms/u-boot/tools/logos/atmel.bmp Binary files differnew file mode 100644 index 000000000..5c659ce87 --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/atmel.bmp diff --git a/qemu/roms/u-boot/tools/logos/denx.bmp b/qemu/roms/u-boot/tools/logos/denx.bmp Binary files differnew file mode 100644 index 000000000..c4cde09d5 --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/denx.bmp diff --git a/qemu/roms/u-boot/tools/logos/esd.bmp b/qemu/roms/u-boot/tools/logos/esd.bmp Binary files differnew file mode 100644 index 000000000..a6b403024 --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/esd.bmp diff --git a/qemu/roms/u-boot/tools/logos/freescale.bmp b/qemu/roms/u-boot/tools/logos/freescale.bmp Binary files differnew file mode 100644 index 000000000..1589e8073 --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/freescale.bmp diff --git a/qemu/roms/u-boot/tools/logos/intercontrol.bmp b/qemu/roms/u-boot/tools/logos/intercontrol.bmp Binary files differnew file mode 100644 index 000000000..cf2a884b2 --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/intercontrol.bmp diff --git a/qemu/roms/u-boot/tools/logos/linux_logo_ttcontrol.bmp b/qemu/roms/u-boot/tools/logos/linux_logo_ttcontrol.bmp Binary files differnew file mode 100644 index 000000000..031d3a41e --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/linux_logo_ttcontrol.bmp diff --git a/qemu/roms/u-boot/tools/logos/linux_logo_ttcontrol_palfin.bmp b/qemu/roms/u-boot/tools/logos/linux_logo_ttcontrol_palfin.bmp Binary files differnew file mode 100644 index 000000000..e3e38d1bf --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/linux_logo_ttcontrol_palfin.bmp diff --git a/qemu/roms/u-boot/tools/logos/ronetix.bmp b/qemu/roms/u-boot/tools/logos/ronetix.bmp Binary files differnew file mode 100644 index 000000000..f95681391 --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/ronetix.bmp diff --git a/qemu/roms/u-boot/tools/logos/siemens.bmp b/qemu/roms/u-boot/tools/logos/siemens.bmp Binary files differnew file mode 100644 index 000000000..bff2b190e --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/siemens.bmp diff --git a/qemu/roms/u-boot/tools/logos/syteco.bmp b/qemu/roms/u-boot/tools/logos/syteco.bmp Binary files differnew file mode 100644 index 000000000..14031f2c8 --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/syteco.bmp diff --git a/qemu/roms/u-boot/tools/logos/wandboard.bmp b/qemu/roms/u-boot/tools/logos/wandboard.bmp Binary files differnew file mode 100644 index 000000000..7f288a8e8 --- /dev/null +++ b/qemu/roms/u-boot/tools/logos/wandboard.bmp diff --git a/qemu/roms/u-boot/tools/md5.c b/qemu/roms/u-boot/tools/md5.c new file mode 100644 index 000000000..befaa321c --- /dev/null +++ b/qemu/roms/u-boot/tools/md5.c @@ -0,0 +1 @@ +#include "../lib/md5.c" diff --git a/qemu/roms/u-boot/tools/mingw_support.c b/qemu/roms/u-boot/tools/mingw_support.c new file mode 100644 index 000000000..95c4db892 --- /dev/null +++ b/qemu/roms/u-boot/tools/mingw_support.c @@ -0,0 +1,116 @@ +/* + * Copyright 2008 Extreme Engineering Solutions, Inc. + * + * mmap/munmap implementation derived from: + * Clamav Native Windows Port : mmap win32 compatibility layer + * Copyright (c) 2005-2006 Gianluigi Tiesi <sherpya@netfarm.it> + * Parts by Kees Zeelenberg <kzlg@users.sourceforge.net> (LibGW32C) + * + * SPDX-License-Identifier: LGPL-2.0+ + */ + +#include "mingw_support.h" +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include <io.h> + +int fsync(int fd) +{ + return _commit(fd); +} + +void *mmap(void *addr, size_t len, int prot, int flags, int fd, int offset) +{ + void *map = NULL; + HANDLE handle = INVALID_HANDLE_VALUE; + DWORD cfm_flags = 0, mvf_flags = 0; + + switch (prot) { + case PROT_READ | PROT_WRITE: + cfm_flags = PAGE_READWRITE; + mvf_flags = FILE_MAP_ALL_ACCESS; + break; + case PROT_WRITE: + cfm_flags = PAGE_READWRITE; + mvf_flags = FILE_MAP_WRITE; + break; + case PROT_READ: + cfm_flags = PAGE_READONLY; + mvf_flags = FILE_MAP_READ; + break; + default: + return MAP_FAILED; + } + + handle = CreateFileMappingA((HANDLE) _get_osfhandle(fd), NULL, + cfm_flags, HIDWORD(len), LODWORD(len), NULL); + if (!handle) + return MAP_FAILED; + + map = MapViewOfFile(handle, mvf_flags, HIDWORD(offset), + LODWORD(offset), len); + CloseHandle(handle); + + if (!map) + return MAP_FAILED; + + return map; +} + +int munmap(void *addr, size_t len) +{ + if (!UnmapViewOfFile(addr)) + return -1; + + return 0; +} + +/* Reentrant string tokenizer. Generic version. + Copyright (C) 1991,1996-1999,2001,2004,2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Parse S into tokens separated by characters in DELIM. + If S is NULL, the saved pointer in SAVE_PTR is used as + the next starting point. For example: + char s[] = "-abc-=-def"; + char *sp; + x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def" + x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL + x = strtok_r(NULL, "=", &sp); // x = NULL + // s = "abc\0-def\0" +*/ +char *strtok_r(char *s, const char *delim, char **save_ptr) +{ + char *token; + + if (s == NULL) + s = *save_ptr; + + /* Scan leading delimiters. */ + s += strspn(s, delim); + if (*s == '\0') { + *save_ptr = s; + return NULL; + } + + /* Find the end of the token. */ + token = s; + s = strpbrk (token, delim); + if (s == NULL) { + /* This token finishes the string. */ + *save_ptr = memchr(token, '\0', strlen(token)); + } else { + /* Terminate the token and make *SAVE_PTR point past it. */ + *s = '\0'; + *save_ptr = s + 1; + } + return token; +} + +#include "getline.c" diff --git a/qemu/roms/u-boot/tools/mingw_support.h b/qemu/roms/u-boot/tools/mingw_support.h new file mode 100644 index 000000000..f9535b376 --- /dev/null +++ b/qemu/roms/u-boot/tools/mingw_support.h @@ -0,0 +1,46 @@ +/* + * Copyright 2008 Extreme Engineering Solutions, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + */ + +#ifndef __MINGW_SUPPORT_H_ +#define __WINGW_SUPPORT_H_ 1 + +/* Defining __INSIDE_MSYS__ helps to prevent u-boot/mingw overlap */ +#define __INSIDE_MSYS__ 1 + +#include <windows.h> + +/* mmap protections */ +#define PROT_READ 0x1 /* Page can be read */ +#define PROT_WRITE 0x2 /* Page can be written */ +#define PROT_EXEC 0x4 /* Page can be executed */ +#define PROT_NONE 0x0 /* Page can not be accessed */ + +/* Sharing types (must choose one and only one of these) */ +#define MAP_SHARED 0x01 /* Share changes */ +#define MAP_PRIVATE 0x02 /* Changes are private */ + +/* File perms */ +#ifndef S_IRGRP +# define S_IRGRP 0 +#endif +#ifndef S_IWGRP +# define S_IWGRP 0 +#endif + +/* Windows 64-bit access macros */ +#define LODWORD(x) ((DWORD)((DWORDLONG)(x))) +#define HIDWORD(x) ((DWORD)(((DWORDLONG)(x) >> 32) & 0xffffffff)) + +typedef UINT uint; +typedef ULONG ulong; + +int fsync(int fd); +void *mmap(void *, size_t, int, int, int, int); +int munmap(void *, size_t); +char *strtok_r(char *s, const char *delim, char **save_ptr); +#include "getline.h" + +#endif /* __MINGW_SUPPORT_H_ */ diff --git a/qemu/roms/u-boot/tools/mkenvimage.c b/qemu/roms/u-boot/tools/mkenvimage.c new file mode 100644 index 000000000..bbd3041e3 --- /dev/null +++ b/qemu/roms/u-boot/tools/mkenvimage.c @@ -0,0 +1,295 @@ +/* + * (C) Copyright 2011 Free Electrons + * David Wagner <david.wagner@free-electrons.com> + * + * Inspired from envcrc.c: + * (C) Copyright 2001 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <libgen.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include "compiler.h" +#include <u-boot/crc.h> +#include <version.h> + +#define CRC_SIZE sizeof(uint32_t) + +static void usage(const char *exec_name) +{ + fprintf(stderr, "%s [-h] [-r] [-b] [-p <byte>] -s <environment partition size> -o <output> <input file>\n" + "\n" + "This tool takes a key=value input file (same as would a `printenv' show) and generates the corresponding environment image, ready to be flashed.\n" + "\n" + "\tThe input file is in format:\n" + "\t\tkey1=value1\n" + "\t\tkey2=value2\n" + "\t\t...\n" + "\t-r : the environment has multiple copies in flash\n" + "\t-b : the target is big endian (default is little endian)\n" + "\t-p <byte> : fill the image with <byte> bytes instead of 0xff bytes\n" + "\t-V : print version information and exit\n" + "\n" + "If the input file is \"-\", data is read from standard input\n", + exec_name); +} + +long int xstrtol(const char *s) +{ + long int tmp; + + errno = 0; + tmp = strtol(s, NULL, 0); + if (!errno) + return tmp; + + if (errno == ERANGE) + fprintf(stderr, "Bad integer format: %s\n", s); + else + fprintf(stderr, "Error while parsing %s: %s\n", s, + strerror(errno)); + + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + uint32_t crc, targetendian_crc; + const char *txt_filename = NULL, *bin_filename = NULL; + int txt_fd, bin_fd; + unsigned char *dataptr, *envptr; + unsigned char *filebuf = NULL; + unsigned int filesize = 0, envsize = 0, datasize = 0; + int bigendian = 0; + int redundant = 0; + unsigned char padbyte = 0xff; + + int option; + int ret = EXIT_SUCCESS; + + struct stat txt_file_stat; + + int fp, ep; + const char *prg; + + prg = basename(argv[0]); + + /* Turn off getopt()'s internal error message */ + opterr = 0; + + /* Parse the cmdline */ + while ((option = getopt(argc, argv, ":s:o:rbp:hV")) != -1) { + switch (option) { + case 's': + datasize = xstrtol(optarg); + break; + case 'o': + bin_filename = strdup(optarg); + if (!bin_filename) { + fprintf(stderr, "Can't strdup() the output filename\n"); + return EXIT_FAILURE; + } + break; + case 'r': + redundant = 1; + break; + case 'b': + bigendian = 1; + break; + case 'p': + padbyte = xstrtol(optarg); + break; + case 'h': + usage(prg); + return EXIT_SUCCESS; + case 'V': + printf("%s version %s\n", prg, PLAIN_VERSION); + return EXIT_SUCCESS; + case ':': + fprintf(stderr, "Missing argument for option -%c\n", + optopt); + usage(prg); + return EXIT_FAILURE; + default: + fprintf(stderr, "Wrong option -%c\n", optopt); + usage(prg); + return EXIT_FAILURE; + } + } + + /* Check datasize and allocate the data */ + if (datasize == 0) { + fprintf(stderr, "Please specify the size of the environment partition.\n"); + usage(prg); + return EXIT_FAILURE; + } + + dataptr = malloc(datasize * sizeof(*dataptr)); + if (!dataptr) { + fprintf(stderr, "Can't alloc %d bytes for dataptr.\n", + datasize); + return EXIT_FAILURE; + } + + /* + * envptr points to the beginning of the actual environment (after the + * crc and possible `redundant' byte + */ + envsize = datasize - (CRC_SIZE + redundant); + envptr = dataptr + CRC_SIZE + redundant; + + /* Pad the environment with the padding byte */ + memset(envptr, padbyte, envsize); + + /* Open the input file ... */ + if (optind >= argc || strcmp(argv[optind], "-") == 0) { + int readbytes = 0; + int readlen = sizeof(*envptr) * 4096; + txt_fd = STDIN_FILENO; + + do { + filebuf = realloc(filebuf, readlen); + if (!filebuf) { + fprintf(stderr, "Can't realloc memory for the input file buffer\n"); + return EXIT_FAILURE; + } + readbytes = read(txt_fd, filebuf + filesize, readlen); + if (errno) { + fprintf(stderr, "Error while reading stdin: %s\n", + strerror(errno)); + return EXIT_FAILURE; + } + filesize += readbytes; + } while (readbytes == readlen); + + } else { + txt_filename = argv[optind]; + txt_fd = open(txt_filename, O_RDONLY); + if (txt_fd == -1) { + fprintf(stderr, "Can't open \"%s\": %s\n", + txt_filename, strerror(errno)); + return EXIT_FAILURE; + } + /* ... and check it */ + ret = fstat(txt_fd, &txt_file_stat); + if (ret == -1) { + fprintf(stderr, "Can't stat() on \"%s\": %s\n", + txt_filename, strerror(errno)); + return EXIT_FAILURE; + } + + filesize = txt_file_stat.st_size; + + filebuf = mmap(NULL, sizeof(*envptr) * filesize, PROT_READ, + MAP_PRIVATE, txt_fd, 0); + if (filebuf == MAP_FAILED) { + fprintf(stderr, "mmap (%zu bytes) failed: %s\n", + sizeof(*envptr) * filesize, + strerror(errno)); + fprintf(stderr, "Falling back to read()\n"); + + filebuf = malloc(sizeof(*envptr) * filesize); + ret = read(txt_fd, filebuf, sizeof(*envptr) * filesize); + if (ret != sizeof(*envptr) * filesize) { + fprintf(stderr, "Can't read the whole input file (%zu bytes): %s\n", + sizeof(*envptr) * filesize, + strerror(errno)); + + return EXIT_FAILURE; + } + } + ret = close(txt_fd); + } + /* The +1 is for the additionnal ending \0. See below. */ + if (filesize + 1 > envsize) { + fprintf(stderr, "The input file is larger than the environment partition size\n"); + return EXIT_FAILURE; + } + + /* Replace newlines separating variables with \0 */ + for (fp = 0, ep = 0 ; fp < filesize ; fp++) { + if (filebuf[fp] == '\n') { + if (ep == 0) { + /* + * Newlines at the beginning of the file ? + * Ignore them. + */ + continue; + } else if (filebuf[fp-1] == '\\') { + /* + * Embedded newline in a variable. + * + * The backslash was added to the envptr; rewind + * and replace it with a newline + */ + ep--; + envptr[ep++] = '\n'; + } else { + /* End of a variable */ + envptr[ep++] = '\0'; + } + } else { + envptr[ep++] = filebuf[fp]; + } + } + /* + * Make sure there is a final '\0' + * And do it again on the next byte to mark the end of the environment. + */ + if (envptr[ep-1] != '\0') { + envptr[ep++] = '\0'; + /* + * The text file doesn't have an ending newline. We need to + * check the env size again to make sure we have room for two \0 + */ + if (ep >= envsize) { + fprintf(stderr, "The environment file is too large for the target environment storage\n"); + return EXIT_FAILURE; + } + envptr[ep] = '\0'; + } else { + envptr[ep] = '\0'; + } + + /* Computes the CRC and put it at the beginning of the data */ + crc = crc32(0, envptr, envsize); + targetendian_crc = bigendian ? cpu_to_be32(crc) : cpu_to_le32(crc); + + memcpy(dataptr, &targetendian_crc, sizeof(targetendian_crc)); + if (redundant) + dataptr[sizeof(targetendian_crc)] = 1; + + if (!bin_filename || strcmp(bin_filename, "-") == 0) { + bin_fd = STDOUT_FILENO; + } else { + bin_fd = creat(bin_filename, S_IRUSR | S_IWUSR | S_IRGRP | + S_IWGRP); + if (bin_fd == -1) { + fprintf(stderr, "Can't open output file \"%s\": %s\n", + bin_filename, strerror(errno)); + return EXIT_FAILURE; + } + } + + if (write(bin_fd, dataptr, sizeof(*dataptr) * datasize) != + sizeof(*dataptr) * datasize) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + + ret = close(bin_fd); + + return ret; +} diff --git a/qemu/roms/u-boot/tools/mkexynosspl.c b/qemu/roms/u-boot/tools/mkexynosspl.c new file mode 100644 index 000000000..32b786c72 --- /dev/null +++ b/qemu/roms/u-boot/tools/mkexynosspl.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <sys/stat.h> +#include <compiler.h> + +#define CHECKSUM_OFFSET (14*1024-4) +#define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP \ + | S_IWGRP | S_IROTH | S_IWOTH) +/* + * Requirement for the fixed size SPL header: + * IROM code reads first (CHECKSUM_OFFSET + 4) bytes from boot device. It then + * calculates the checksum of CHECKSUM_OFFSET bytes and compares with data at + * CHECKSUM_OFFSET location. + * + * Requirement for the variable size SPL header: + + * IROM code reads the below header to find out the size of the blob (total + * size, header size included) and its checksum. Then it reads the rest of the + * blob [i.e size - sizeof(struct var_size_header) bytes], calculates the + * checksum and compares it with value read from the header. + */ +struct var_size_header { + uint32_t spl_size; + uint32_t spl_checksum; + uint32_t reserved[2]; +}; + +static const char *prog_name; + +static void write_to_file(int ofd, void *buffer, int size) +{ + if (write(ofd, buffer, size) == size) + return; + + fprintf(stderr, "%s: Failed to write to output file: %s\n", + prog_name, strerror(errno)); + exit(EXIT_FAILURE); +} + +/* + * The argv is expected to include one optional parameter and two filenames: + * [--vs] IN OUT + * + * --vs - turns on the variable size SPL mode + * IN - the u-boot SPL binary, usually u-boot-spl.bin + * OUT - the prepared SPL blob, usually ${BOARD}-spl.bin + * + * This utility first reads the "u-boot-spl.bin" into a buffer. In case of + * fixed size SPL the buffer size is exactly CHECKSUM_OFFSET (such that + * smaller u-boot-spl.bin gets padded with 0xff bytes, the larger than limit + * u-boot-spl.bin causes an error). For variable size SPL the buffer size is + * eqaul to size of the IN file. + * + * Then it calculates checksum of the buffer by just summing up all bytes. + * Then + * + * - for fixed size SPL the buffer is written into the output file and the + * checksum is appended to the file in little endian format, which results + * in checksum added exactly at CHECKSUM_OFFSET. + * + * - for variable size SPL the checksum and file size are stored in the + * var_size_header structure (again, in little endian format) and the + * structure is written into the output file. Then the buffer is written + * into the output file. + */ +int main(int argc, char **argv) +{ + unsigned char *buffer; + int i, ifd, ofd; + uint32_t checksum = 0; + off_t len; + int var_size_flag, read_size, count; + struct stat stat; + const int if_index = argc - 2; /* Input file name index in argv. */ + const int of_index = argc - 1; /* Output file name index in argv. */ + + /* Strip path off the program name. */ + prog_name = strrchr(argv[0], '/'); + if (prog_name) + prog_name++; + else + prog_name = argv[0]; + + if ((argc < 3) || + (argc > 4) || + ((argc == 4) && strcmp(argv[1], "--vs"))) { + fprintf(stderr, "Usage: %s [--vs] <infile> <outfile>\n", + prog_name); + exit(EXIT_FAILURE); + } + + /* four args mean variable size SPL wrapper is required */ + var_size_flag = (argc == 4); + + ifd = open(argv[if_index], O_RDONLY); + if (ifd < 0) { + fprintf(stderr, "%s: Can't open %s: %s\n", + prog_name, argv[if_index], strerror(errno)); + exit(EXIT_FAILURE); + } + + ofd = open(argv[of_index], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM); + if (ifd < 0) { + fprintf(stderr, "%s: Can't open %s: %s\n", + prog_name, argv[of_index], strerror(errno)); + exit(EXIT_FAILURE); + } + + if (fstat(ifd, &stat)) { + fprintf(stderr, "%s: Unable to get size of %s: %s\n", + prog_name, argv[if_index], strerror(errno)); + exit(EXIT_FAILURE); + } + + len = stat.st_size; + + if (var_size_flag) { + read_size = len; + count = len; + } else { + if (len > CHECKSUM_OFFSET) { + fprintf(stderr, + "%s: %s is too big (exceeds %d bytes)\n", + prog_name, argv[if_index], CHECKSUM_OFFSET); + exit(EXIT_FAILURE); + } + count = CHECKSUM_OFFSET; + read_size = len; + } + + buffer = malloc(count); + if (!buffer) { + fprintf(stderr, + "%s: Failed to allocate %d bytes to store %s\n", + prog_name, count, argv[if_index]); + exit(EXIT_FAILURE); + } + + if (read(ifd, buffer, read_size) != read_size) { + fprintf(stderr, "%s: Can't read %s: %s\n", + prog_name, argv[if_index], strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Pad if needed with 0xff to make flashing faster. */ + if (read_size < count) + memset((char *)buffer + read_size, 0xff, count - read_size); + + for (i = 0, checksum = 0; i < count; i++) + checksum += buffer[i]; + checksum = cpu_to_le32(checksum); + + if (var_size_flag) { + /* Prepare and write out the variable size SPL header. */ + struct var_size_header vsh; + uint32_t spl_size; + + memset(&vsh, 0, sizeof(vsh)); + memcpy(&vsh.spl_checksum, &checksum, sizeof(checksum)); + + spl_size = cpu_to_le32(count + sizeof(struct var_size_header)); + memcpy(&vsh.spl_size, &spl_size, sizeof(spl_size)); + write_to_file(ofd, &vsh, sizeof(vsh)); + } + + write_to_file(ofd, buffer, count); + + /* For fixed size SPL checksum is appended in the end. */ + if (!var_size_flag) + write_to_file(ofd, &checksum, sizeof(checksum)); + + close(ifd); + close(ofd); + free(buffer); + + return EXIT_SUCCESS; +} diff --git a/qemu/roms/u-boot/tools/mkimage.c b/qemu/roms/u-boot/tools/mkimage.c new file mode 100644 index 000000000..123d0c7d9 --- /dev/null +++ b/qemu/roms/u-boot/tools/mkimage.c @@ -0,0 +1,654 @@ +/* + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2009 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "mkimage.h" +#include <image.h> +#include <version.h> + +static void copy_file(int, const char *, int); +static void usage(void); + +/* image_type_params link list to maintain registered image type supports */ +struct image_type_params *mkimage_tparams = NULL; + +/* parameters initialized by core will be used by the image type code */ +struct image_tool_params params = { + .os = IH_OS_LINUX, + .arch = IH_ARCH_PPC, + .type = IH_TYPE_KERNEL, + .comp = IH_COMP_GZIP, + .dtc = MKIMAGE_DEFAULT_DTC_OPTIONS, + .imagename = "", + .imagename2 = "", +}; + +/* + * mkimage_register - + * + * It is used to register respective image generation/list support to the + * mkimage core + * + * the input struct image_type_params is checked and appended to the link + * list, if the input structure is already registered, error + */ +void mkimage_register (struct image_type_params *tparams) +{ + struct image_type_params **tp; + + if (!tparams) { + fprintf (stderr, "%s: %s: Null input\n", + params.cmdname, __FUNCTION__); + exit (EXIT_FAILURE); + } + + /* scan the linked list, check for registry and point the last one */ + for (tp = &mkimage_tparams; *tp != NULL; tp = &(*tp)->next) { + if (!strcmp((*tp)->name, tparams->name)) { + fprintf (stderr, "%s: %s already registered\n", + params.cmdname, tparams->name); + return; + } + } + + /* add input struct entry at the end of link list */ + *tp = tparams; + /* mark input entry as last entry in the link list */ + tparams->next = NULL; + + debug ("Registered %s\n", tparams->name); +} + +/* + * mkimage_get_type - + * + * It scans all registers image type supports + * checks the input type_id for each supported image type + * + * if successful, + * returns respective image_type_params pointer if success + * if input type_id is not supported by any of image_type_support + * returns NULL + */ +struct image_type_params *mkimage_get_type(int type) +{ + struct image_type_params *curr; + + for (curr = mkimage_tparams; curr != NULL; curr = curr->next) { + if (curr->check_image_type) { + if (!curr->check_image_type (type)) + return curr; + } + } + return NULL; +} + +/* + * mkimage_verify_print_header - + * + * It scans mkimage_tparams link list, + * verifies image_header for each supported image type + * if verification is successful, prints respective header + * + * returns negative if input image format does not match with any of + * supported image types + */ +int mkimage_verify_print_header (void *ptr, struct stat *sbuf) +{ + int retval = -1; + struct image_type_params *curr; + + for (curr = mkimage_tparams; curr != NULL; curr = curr->next ) { + if (curr->verify_header) { + retval = curr->verify_header ( + (unsigned char *)ptr, sbuf->st_size, + ¶ms); + + if (retval == 0) { + /* + * Print the image information + * if verify is successful + */ + if (curr->print_header) + curr->print_header (ptr); + else { + fprintf (stderr, + "%s: print_header undefined for %s\n", + params.cmdname, curr->name); + } + break; + } + } + } + return retval; +} + +int +main (int argc, char **argv) +{ + int ifd = -1; + struct stat sbuf; + char *ptr; + int retval = 0; + struct image_type_params *tparams = NULL; + int pad_len = 0; + + /* Init all image generation/list support */ + register_image_tool(mkimage_register); + + params.cmdname = *argv; + params.addr = params.ep = 0; + + while (--argc > 0 && **++argv == '-') { + while (*++*argv) { + switch (**argv) { + case 'l': + params.lflag = 1; + break; + case 'A': + if ((--argc <= 0) || + (params.arch = + genimg_get_arch_id (*++argv)) < 0) + usage (); + goto NXTARG; + case 'c': + if (--argc <= 0) + usage(); + params.comment = *++argv; + goto NXTARG; + case 'C': + if ((--argc <= 0) || + (params.comp = + genimg_get_comp_id (*++argv)) < 0) + usage (); + goto NXTARG; + case 'D': + if (--argc <= 0) + usage (); + params.dtc = *++argv; + goto NXTARG; + + case 'O': + if ((--argc <= 0) || + (params.os = + genimg_get_os_id (*++argv)) < 0) + usage (); + goto NXTARG; + case 'T': + if ((--argc <= 0) || + (params.type = + genimg_get_type_id (*++argv)) < 0) + usage (); + goto NXTARG; + + case 'a': + if (--argc <= 0) + usage (); + params.addr = strtoul (*++argv, &ptr, 16); + if (*ptr) { + fprintf (stderr, + "%s: invalid load address %s\n", + params.cmdname, *argv); + exit (EXIT_FAILURE); + } + goto NXTARG; + case 'd': + if (--argc <= 0) + usage (); + params.datafile = *++argv; + params.dflag = 1; + goto NXTARG; + case 'e': + if (--argc <= 0) + usage (); + params.ep = strtoul (*++argv, &ptr, 16); + if (*ptr) { + fprintf (stderr, + "%s: invalid entry point %s\n", + params.cmdname, *argv); + exit (EXIT_FAILURE); + } + params.eflag = 1; + goto NXTARG; + case 'f': + if (--argc <= 0) + usage (); + params.datafile = *++argv; + /* no break */ + case 'F': + /* + * The flattened image tree (FIT) format + * requires a flattened device tree image type + */ + params.type = IH_TYPE_FLATDT; + params.fflag = 1; + goto NXTARG; + case 'k': + if (--argc <= 0) + usage(); + params.keydir = *++argv; + goto NXTARG; + case 'K': + if (--argc <= 0) + usage(); + params.keydest = *++argv; + goto NXTARG; + case 'n': + if (--argc <= 0) + usage (); + params.imagename = *++argv; + goto NXTARG; + case 'r': + params.require_keys = 1; + break; + case 'R': + if (--argc <= 0) + usage(); + /* + * This entry is for the second configuration + * file, if only one is not enough. + */ + params.imagename2 = *++argv; + goto NXTARG; + case 's': + params.skipcpy = 1; + break; + case 'v': + params.vflag++; + break; + case 'V': + printf("mkimage version %s\n", PLAIN_VERSION); + exit(EXIT_SUCCESS); + case 'x': + params.xflag++; + break; + default: + usage (); + } + } +NXTARG: ; + } + + if (argc != 1) + usage (); + + /* set tparams as per input type_id */ + tparams = mkimage_get_type(params.type); + if (tparams == NULL) { + fprintf (stderr, "%s: unsupported type %s\n", + params.cmdname, genimg_get_type_name(params.type)); + exit (EXIT_FAILURE); + } + + /* + * check the passed arguments parameters meets the requirements + * as per image type to be generated/listed + */ + if (tparams->check_params) + if (tparams->check_params (¶ms)) + usage (); + + if (!params.eflag) { + params.ep = params.addr; + /* If XIP, entry point must be after the U-Boot header */ + if (params.xflag) + params.ep += tparams->header_size; + } + + params.imagefile = *argv; + + if (params.fflag){ + if (tparams->fflag_handle) + /* + * in some cases, some additional processing needs + * to be done if fflag is defined + * + * For ex. fit_handle_file for Fit file support + */ + retval = tparams->fflag_handle(¶ms); + + if (retval != EXIT_SUCCESS) + exit (retval); + } + + if (params.lflag || params.fflag) { + ifd = open (params.imagefile, O_RDONLY|O_BINARY); + } else { + ifd = open (params.imagefile, + O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); + } + + if (ifd < 0) { + fprintf (stderr, "%s: Can't open %s: %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit (EXIT_FAILURE); + } + + if (params.lflag || params.fflag) { + /* + * list header information of existing image + */ + if (fstat(ifd, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit (EXIT_FAILURE); + } + + if ((unsigned)sbuf.st_size < tparams->header_size) { + fprintf (stderr, + "%s: Bad size: \"%s\" is not valid image\n", + params.cmdname, params.imagefile); + exit (EXIT_FAILURE); + } + + ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0); + if (ptr == MAP_FAILED) { + fprintf (stderr, "%s: Can't read %s: %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit (EXIT_FAILURE); + } + + /* + * scan through mkimage registry for all supported image types + * and verify the input image file header for match + * Print the image information for matched image type + * Returns the error code if not matched + */ + retval = mkimage_verify_print_header (ptr, &sbuf); + + (void) munmap((void *)ptr, sbuf.st_size); + (void) close (ifd); + + exit (retval); + } + + /* + * In case there an header with a variable + * length will be added, the corresponding + * function is called. This is responsible to + * allocate memory for the header itself. + */ + if (tparams->vrec_header) + pad_len = tparams->vrec_header(¶ms, tparams); + else + memset(tparams->hdr, 0, tparams->header_size); + + if (write(ifd, tparams->hdr, tparams->header_size) + != tparams->header_size) { + fprintf (stderr, "%s: Write error on %s: %s\n", + params.cmdname, params.imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (!params.skipcpy) { + if (params.type == IH_TYPE_MULTI || + params.type == IH_TYPE_SCRIPT) { + char *file = params.datafile; + uint32_t size; + + for (;;) { + char *sep = NULL; + + if (file) { + if ((sep = strchr(file, ':')) != NULL) { + *sep = '\0'; + } + + if (stat (file, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + params.cmdname, file, strerror(errno)); + exit (EXIT_FAILURE); + } + size = cpu_to_uimage (sbuf.st_size); + } else { + size = 0; + } + + if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { + fprintf (stderr, "%s: Write error on %s: %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit (EXIT_FAILURE); + } + + if (!file) { + break; + } + + if (sep) { + *sep = ':'; + file = sep + 1; + } else { + file = NULL; + } + } + + file = params.datafile; + + for (;;) { + char *sep = strchr(file, ':'); + if (sep) { + *sep = '\0'; + copy_file (ifd, file, 1); + *sep++ = ':'; + file = sep; + } else { + copy_file (ifd, file, 0); + break; + } + } + } else if (params.type == IH_TYPE_PBLIMAGE) { + /* PBL has special Image format, implements its' own */ + pbl_load_uboot(ifd, ¶ms); + } else { + copy_file(ifd, params.datafile, pad_len); + } + } + + /* We're a bit of paranoid */ +#if defined(_POSIX_SYNCHRONIZED_IO) && \ + !defined(__sun__) && \ + !defined(__FreeBSD__) && \ + !defined(__APPLE__) + (void) fdatasync (ifd); +#else + (void) fsync (ifd); +#endif + + if (fstat(ifd, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + params.cmdname, params.imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); + if (ptr == MAP_FAILED) { + fprintf (stderr, "%s: Can't map %s: %s\n", + params.cmdname, params.imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + /* Setup the image header as per input image type*/ + if (tparams->set_header) + tparams->set_header (ptr, &sbuf, ifd, ¶ms); + else { + fprintf (stderr, "%s: Can't set header for %s: %s\n", + params.cmdname, tparams->name, strerror(errno)); + exit (EXIT_FAILURE); + } + + /* Print the image information by processing image header */ + if (tparams->print_header) + tparams->print_header (ptr); + else { + fprintf (stderr, "%s: Can't print header for %s: %s\n", + params.cmdname, tparams->name, strerror(errno)); + exit (EXIT_FAILURE); + } + + (void) munmap((void *)ptr, sbuf.st_size); + + /* We're a bit of paranoid */ +#if defined(_POSIX_SYNCHRONIZED_IO) && \ + !defined(__sun__) && \ + !defined(__FreeBSD__) && \ + !defined(__APPLE__) + (void) fdatasync (ifd); +#else + (void) fsync (ifd); +#endif + + if (close(ifd)) { + fprintf (stderr, "%s: Write error on %s: %s\n", + params.cmdname, params.imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); +} + +static void +copy_file (int ifd, const char *datafile, int pad) +{ + int dfd; + struct stat sbuf; + unsigned char *ptr; + int tail; + int zero = 0; + uint8_t zeros[4096]; + int offset = 0; + int size; + struct image_type_params *tparams = mkimage_get_type (params.type); + + if (pad >= sizeof(zeros)) { + fprintf(stderr, "%s: Can't pad to %d\n", + params.cmdname, pad); + exit(EXIT_FAILURE); + } + + memset(zeros, 0, sizeof(zeros)); + + if (params.vflag) { + fprintf (stderr, "Adding Image %s\n", datafile); + } + + if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { + fprintf (stderr, "%s: Can't open %s: %s\n", + params.cmdname, datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (fstat(dfd, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + params.cmdname, datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); + if (ptr == MAP_FAILED) { + fprintf (stderr, "%s: Can't read %s: %s\n", + params.cmdname, datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (params.xflag) { + unsigned char *p = NULL; + /* + * XIP: do not append the image_header_t at the + * beginning of the file, but consume the space + * reserved for it. + */ + + if ((unsigned)sbuf.st_size < tparams->header_size) { + fprintf (stderr, + "%s: Bad size: \"%s\" is too small for XIP\n", + params.cmdname, datafile); + exit (EXIT_FAILURE); + } + + for (p = ptr; p < ptr + tparams->header_size; p++) { + if ( *p != 0xff ) { + fprintf (stderr, + "%s: Bad file: \"%s\" has invalid buffer for XIP\n", + params.cmdname, datafile); + exit (EXIT_FAILURE); + } + } + + offset = tparams->header_size; + } + + size = sbuf.st_size - offset; + if (write(ifd, ptr + offset, size) != size) { + fprintf (stderr, "%s: Write error on %s: %s\n", + params.cmdname, params.imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + tail = size % 4; + if ((pad == 1) && (tail != 0)) { + + if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { + fprintf (stderr, "%s: Write error on %s: %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit (EXIT_FAILURE); + } + } else if (pad > 1) { + if (write(ifd, (char *)&zeros, pad) != pad) { + fprintf(stderr, "%s: Write error on %s: %s\n", + params.cmdname, params.imagefile, + strerror(errno)); + exit(EXIT_FAILURE); + } + } + + (void) munmap((void *)ptr, sbuf.st_size); + (void) close (dfd); +} + +static void usage(void) +{ + fprintf (stderr, "Usage: %s -l image\n" + " -l ==> list image header information\n", + params.cmdname); + fprintf (stderr, " %s [-x] -A arch -O os -T type -C comp " + "-a addr -e ep -n name -d data_file[:data_file...] image\n" + " -A ==> set architecture to 'arch'\n" + " -O ==> set operating system to 'os'\n" + " -T ==> set image type to 'type'\n" + " -C ==> set compression type 'comp'\n" + " -a ==> set load address to 'addr' (hex)\n" + " -e ==> set entry point to 'ep' (hex)\n" + " -n ==> set image name to 'name'\n" + " -d ==> use image data from 'datafile'\n" + " -x ==> set XIP (execute in place)\n", + params.cmdname); + fprintf(stderr, " %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n", + params.cmdname); + fprintf(stderr, " -D => set options for device tree compiler\n" + " -f => input filename for FIT source\n"); +#ifdef CONFIG_FIT_SIGNATURE + fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n" + " -k => set directory containing private keys\n" + " -K => write public keys to this .dtb file\n" + " -c => add comment in signature node\n" + " -F => re-sign existing FIT image\n" + " -r => mark keys used as 'required' in dtb\n"); +#else + fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n"); +#endif + fprintf (stderr, " %s -V ==> print version information and exit\n", + params.cmdname); + + exit (EXIT_FAILURE); +} diff --git a/qemu/roms/u-boot/tools/mkimage.h b/qemu/roms/u-boot/tools/mkimage.h new file mode 100644 index 000000000..d5491b6e6 --- /dev/null +++ b/qemu/roms/u-boot/tools/mkimage.h @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2000-2004 + * DENX Software Engineering + * Wolfgang Denk, wd@denx.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _MKIIMAGE_H_ +#define _MKIIMAGE_H_ + +#include "os_support.h" +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> +#include <sha1.h> +#include "fdt_host.h" +#include "imagetool.h" + +#undef MKIMAGE_DEBUG + +#ifdef MKIMAGE_DEBUG +#define debug(fmt,args...) printf (fmt ,##args) +#else +#define debug(fmt,args...) +#endif /* MKIMAGE_DEBUG */ + +static inline void *map_sysmem(ulong paddr, unsigned long len) +{ + return (void *)(uintptr_t)paddr; +} + +static inline ulong map_to_sysmem(void *ptr) +{ + return (ulong)(uintptr_t)ptr; +} + +#define MKIMAGE_TMPFILE_SUFFIX ".tmp" +#define MKIMAGE_MAX_TMPFILE_LEN 256 +#define MKIMAGE_DEFAULT_DTC_OPTIONS "-I dts -O dtb -p 500" +#define MKIMAGE_MAX_DTC_CMDLINE_LEN 512 +#define MKIMAGE_DTC "dtc" /* assume dtc is in $PATH */ + +#endif /* _MKIIMAGE_H_ */ diff --git a/qemu/roms/u-boot/tools/mpc86x_clk.c b/qemu/roms/u-boot/tools/mpc86x_clk.c new file mode 100644 index 000000000..9f662f73e --- /dev/null +++ b/qemu/roms/u-boot/tools/mpc86x_clk.c @@ -0,0 +1,202 @@ +/* + * (C) Copyright 2003 Intracom S.A. + * Pantelis Antoniou <panto@intracom.gr> + * + * This little program makes an exhaustive search for the + * correct terms of pdf, mfi, mfn, mfd, s, dbrmo, in PLPRCR. + * The goal is to produce a gclk2 from a xin input, while respecting + * all the restrictions on their combination. + * + * Generaly you select the first row of the produced table. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + +#include <stdio.h> +#include <stdlib.h> + +#define DPREF_MIN 10000000 +#define DPREF_MAX 32000000 + +#define DPGDCK_MAX 320000000 +#define DPGDCK_MIN 160000000 + +#define S_MIN 0 +#define S_MAX 2 + +#define MFI_MIN 5 +#define MFI_MAX 15 + +#define MFN_MIN 0 +#define MFN_MAX 15 + +#define MFD_MIN 0 +#define MFD_MAX 31 + +#define MF_MIN 5 +#define MF_MAX 15 + +#define PDF_MIN 0 +#define PDF_MAX 15 + +#define GCLK2_MAX 150000000 + +static int calculate (int xin, int target_clock, + int ppm, int pdf, int mfi, int mfn, int mfd, int s, + int *dprefp, int *dpgdckp, int *jdbckp, + int *gclk2p, int *dbrmop) +{ + unsigned int dpref, dpgdck, jdbck, gclk2, t1, t2, dbrmo; + + /* valid MFI? */ + if (mfi < MFI_MIN) + return -1; + + /* valid num, denum? */ + if (mfn > 0 && mfn >= mfd) + return -1; + + dpref = xin / (pdf + 1); + + /* valid dpef? */ + if (dpref < DPREF_MIN || dpref > DPREF_MAX) + return -1; + + if (mfn == 0) { + dpgdck = (2 * mfi * xin) / (pdf + 1) ; + dbrmo = 0; + } else { + /* 5 <= mfi + (mfn / mfd + 1) <= 15 */ + t1 = mfd + 1; + t2 = mfi * t1 + mfn; + if ( MF_MIN * t1 > t2 || MF_MAX * t1 < t2) + return -1; + + dpgdck = (unsigned int)(2 * (mfi * mfd + mfi + mfn) * + (unsigned int)xin) / + ((mfd + 1) * (pdf + 1)); + + dbrmo = 10 * mfn < (mfd + 1); + } + + /* valid dpgclk? */ + if (dpgdck < DPGDCK_MIN || dpgdck > DPGDCK_MAX) + return -1; + + jdbck = dpgdck >> s; + gclk2 = jdbck / 2; + + /* valid gclk2 */ + if (gclk2 > GCLK2_MAX) + return -1; + + t1 = abs(gclk2 - target_clock); + + /* XXX max 1MHz dev. in clock */ + if (t1 > 1000000) + return -1; + + /* dev within range (XXX gclk2 scaled to avoid overflow) */ + if (t1 * 1000 > (unsigned int)ppm * (gclk2 / 1000)) + return -1; + + *dprefp = dpref; + *dpgdckp = dpgdck; + *jdbckp = jdbck; + *gclk2p = gclk2; + *dbrmop = dbrmo; + + return gclk2; +} + +int conf_clock(int xin, int target_clock, int ppm) +{ + int pdf, s, mfn, mfd, mfi; + int dpref, dpgdck, jdbck, gclk2, xout, dbrmo; + int found = 0; + + /* integer multipliers */ + for (pdf = PDF_MIN; pdf <= PDF_MAX; pdf++) { + for (mfi = MFI_MIN; mfi <= MFI_MAX; mfi++) { + for (s = 0; s <= S_MAX; s++) { + xout = calculate(xin, target_clock, + ppm, pdf, mfi, 0, 0, s, + &dpref, &dpgdck, &jdbck, + &gclk2, &dbrmo); + if (xout < 0) + continue; + + if (found == 0) { + printf("pdf mfi mfn mfd s dbrmo dpref dpgdck jdbck gclk2 exact?\n"); + printf("--- --- --- --- - ----- ----- ------ ----- ----- ------\n"); + } + + printf("%3d %3d --- --- %1d %5d %9d %9d %9d %9d%s\n", + pdf, mfi, s, dbrmo, + dpref, dpgdck, jdbck, gclk2, + gclk2 == target_clock ? " YES" : ""); + + found++; + } + } + } + + /* fractional multipliers */ + for (pdf = PDF_MIN; pdf <= PDF_MAX; pdf++) { + for (mfi = MFI_MIN; mfi <= MFI_MAX; mfi++) { + for (mfn = 1; mfn <= MFN_MAX; mfn++) { + for (mfd = 1; mfd <= MFD_MAX; mfd++) { + for (s = 0; s <= S_MAX; s++) { + xout = calculate(xin, target_clock, + ppm, pdf, mfi, mfn, mfd, s, + &dpref, &dpgdck, &jdbck, + &gclk2, &dbrmo); + if (xout < 0) + continue; + + if (found == 0) { + printf("pdf mfi mfn mfd s dbrmo dpref dpgdck jdbck gclk2 exact?\n"); + printf("--- --- --- --- - ----- ----- ------ ----- ----- ------\n"); + } + + printf("%3d %3d %3d %3d %1d %5d %9d %9d %9d %9d%s\n", + pdf, mfi, mfn, mfd, s, + dbrmo, dpref, dpgdck, jdbck, gclk2, + gclk2 == target_clock ? " YES" : ""); + + found++; + } + } + } + + } + } + + return found; +} + +int main(int argc, char *argv[]) +{ + int xin, want_gclk2, found, ppm = 100; + + if (argc < 3) { + fprintf(stderr, "usage: mpc86x_clk <xin> <want_gclk2> [ppm]\n"); + fprintf(stderr, " default ppm is 100\n"); + return 10; + } + + xin = atoi(argv[1]); + want_gclk2 = atoi(argv[2]); + if (argc >= 4) + ppm = atoi(argv[3]); + + found = conf_clock(xin, want_gclk2, ppm); + if (found <= 0) { + fprintf(stderr, "cannot produce gclk2 %d from xin %d\n", + want_gclk2, xin); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/qemu/roms/u-boot/tools/mxsboot.c b/qemu/roms/u-boot/tools/mxsboot.c new file mode 100644 index 000000000..90b21737b --- /dev/null +++ b/qemu/roms/u-boot/tools/mxsboot.c @@ -0,0 +1,673 @@ +/* + * Freescale i.MX28 image generator + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "compiler.h" + +/* + * Default BCB layout. + * + * TWEAK this if you have blown any OCOTP fuses. + */ +#define STRIDE_PAGES 64 +#define STRIDE_COUNT 4 + +/* + * Layout for 256Mb big NAND with 2048b page size, 64b OOB size and + * 128kb erase size. + * + * TWEAK this if you have different kind of NAND chip. + */ +static uint32_t nand_writesize = 2048; +static uint32_t nand_oobsize = 64; +static uint32_t nand_erasesize = 128 * 1024; + +/* + * Sector on which the SigmaTel boot partition (0x53) starts. + */ +static uint32_t sd_sector = 2048; + +/* + * Each of the U-Boot bootstreams is at maximum 1MB big. + * + * TWEAK this if, for some wild reason, you need to boot bigger image. + */ +#define MAX_BOOTSTREAM_SIZE (1 * 1024 * 1024) + +/* i.MX28 NAND controller-specific constants. DO NOT TWEAK! */ +#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4 +#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512 +#define MXS_NAND_METADATA_SIZE 10 +#define MXS_NAND_COMMAND_BUFFER_SIZE 32 + +struct mx28_nand_fcb { + uint32_t checksum; + uint32_t fingerprint; + uint32_t version; + struct { + uint8_t data_setup; + uint8_t data_hold; + uint8_t address_setup; + uint8_t dsample_time; + uint8_t nand_timing_state; + uint8_t rea; + uint8_t rloh; + uint8_t rhoh; + } timing; + uint32_t page_data_size; + uint32_t total_page_size; + uint32_t sectors_per_block; + uint32_t number_of_nands; /* Ignored */ + uint32_t total_internal_die; /* Ignored */ + uint32_t cell_type; /* Ignored */ + uint32_t ecc_block_n_ecc_type; + uint32_t ecc_block_0_size; + uint32_t ecc_block_n_size; + uint32_t ecc_block_0_ecc_type; + uint32_t metadata_bytes; + uint32_t num_ecc_blocks_per_page; + uint32_t ecc_block_n_ecc_level_sdk; /* Ignored */ + uint32_t ecc_block_0_size_sdk; /* Ignored */ + uint32_t ecc_block_n_size_sdk; /* Ignored */ + uint32_t ecc_block_0_ecc_level_sdk; /* Ignored */ + uint32_t num_ecc_blocks_per_page_sdk; /* Ignored */ + uint32_t metadata_bytes_sdk; /* Ignored */ + uint32_t erase_threshold; + uint32_t boot_patch; + uint32_t patch_sectors; + uint32_t firmware1_starting_sector; + uint32_t firmware2_starting_sector; + uint32_t sectors_in_firmware1; + uint32_t sectors_in_firmware2; + uint32_t dbbt_search_area_start_address; + uint32_t badblock_marker_byte; + uint32_t badblock_marker_start_bit; + uint32_t bb_marker_physical_offset; +}; + +struct mx28_nand_dbbt { + uint32_t checksum; + uint32_t fingerprint; + uint32_t version; + uint32_t number_bb; + uint32_t number_2k_pages_bb; +}; + +struct mx28_nand_bbt { + uint32_t nand; + uint32_t number_bb; + uint32_t badblock[510]; +}; + +struct mx28_sd_drive_info { + uint32_t chip_num; + uint32_t drive_type; + uint32_t tag; + uint32_t first_sector_number; + uint32_t sector_count; +}; + +struct mx28_sd_config_block { + uint32_t signature; + uint32_t primary_boot_tag; + uint32_t secondary_boot_tag; + uint32_t num_copies; + struct mx28_sd_drive_info drv_info[1]; +}; + +static inline uint32_t mx28_nand_ecc_size_in_bits(uint32_t ecc_strength) +{ + return ecc_strength * 13; +} + +static inline uint32_t mx28_nand_get_ecc_strength(uint32_t page_data_size, + uint32_t page_oob_size) +{ + if (page_data_size == 2048) + return 8; + + if (page_data_size == 4096) { + if (page_oob_size == 128) + return 8; + + if (page_oob_size == 218) + return 16; + } + + return 0; +} + +static inline uint32_t mx28_nand_get_mark_offset(uint32_t page_data_size, + uint32_t ecc_strength) +{ + uint32_t chunk_data_size_in_bits; + uint32_t chunk_ecc_size_in_bits; + uint32_t chunk_total_size_in_bits; + uint32_t block_mark_chunk_number; + uint32_t block_mark_chunk_bit_offset; + uint32_t block_mark_bit_offset; + + chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8; + chunk_ecc_size_in_bits = mx28_nand_ecc_size_in_bits(ecc_strength); + + chunk_total_size_in_bits = + chunk_data_size_in_bits + chunk_ecc_size_in_bits; + + /* Compute the bit offset of the block mark within the physical page. */ + block_mark_bit_offset = page_data_size * 8; + + /* Subtract the metadata bits. */ + block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8; + + /* + * Compute the chunk number (starting at zero) in which the block mark + * appears. + */ + block_mark_chunk_number = + block_mark_bit_offset / chunk_total_size_in_bits; + + /* + * Compute the bit offset of the block mark within its chunk, and + * validate it. + */ + block_mark_chunk_bit_offset = block_mark_bit_offset - + (block_mark_chunk_number * chunk_total_size_in_bits); + + if (block_mark_chunk_bit_offset > chunk_data_size_in_bits) + return 1; + + /* + * Now that we know the chunk number in which the block mark appears, + * we can subtract all the ECC bits that appear before it. + */ + block_mark_bit_offset -= + block_mark_chunk_number * chunk_ecc_size_in_bits; + + return block_mark_bit_offset; +} + +static inline uint32_t mx28_nand_mark_byte_offset(void) +{ + uint32_t ecc_strength; + ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize); + return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) >> 3; +} + +static inline uint32_t mx28_nand_mark_bit_offset(void) +{ + uint32_t ecc_strength; + ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize); + return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) & 0x7; +} + +static uint32_t mx28_nand_block_csum(uint8_t *block, uint32_t size) +{ + uint32_t csum = 0; + int i; + + for (i = 0; i < size; i++) + csum += block[i]; + + return csum ^ 0xffffffff; +} + +static struct mx28_nand_fcb *mx28_nand_get_fcb(uint32_t size) +{ + struct mx28_nand_fcb *fcb; + uint32_t bcb_size_bytes; + uint32_t stride_size_bytes; + uint32_t bootstream_size_pages; + uint32_t fw1_start_page; + uint32_t fw2_start_page; + + fcb = malloc(nand_writesize); + if (!fcb) { + printf("MX28 NAND: Unable to allocate FCB\n"); + return NULL; + } + + memset(fcb, 0, nand_writesize); + + fcb->fingerprint = 0x20424346; + fcb->version = 0x01000000; + + /* + * FIXME: These here are default values as found in kobs-ng. We should + * probably retrieve the data from NAND or something. + */ + fcb->timing.data_setup = 80; + fcb->timing.data_hold = 60; + fcb->timing.address_setup = 25; + fcb->timing.dsample_time = 6; + + fcb->page_data_size = nand_writesize; + fcb->total_page_size = nand_writesize + nand_oobsize; + fcb->sectors_per_block = nand_erasesize / nand_writesize; + + fcb->num_ecc_blocks_per_page = (nand_writesize / 512) - 1; + fcb->ecc_block_0_size = 512; + fcb->ecc_block_n_size = 512; + fcb->metadata_bytes = 10; + + if (nand_writesize == 2048) { + fcb->ecc_block_n_ecc_type = 4; + fcb->ecc_block_0_ecc_type = 4; + } else if (nand_writesize == 4096) { + if (nand_oobsize == 128) { + fcb->ecc_block_n_ecc_type = 4; + fcb->ecc_block_0_ecc_type = 4; + } else if (nand_oobsize == 218) { + fcb->ecc_block_n_ecc_type = 8; + fcb->ecc_block_0_ecc_type = 8; + } + } + + if (fcb->ecc_block_n_ecc_type == 0) { + printf("MX28 NAND: Unsupported NAND geometry\n"); + goto err; + } + + fcb->boot_patch = 0; + fcb->patch_sectors = 0; + + fcb->badblock_marker_byte = mx28_nand_mark_byte_offset(); + fcb->badblock_marker_start_bit = mx28_nand_mark_bit_offset(); + fcb->bb_marker_physical_offset = nand_writesize; + + stride_size_bytes = STRIDE_PAGES * nand_writesize; + bcb_size_bytes = stride_size_bytes * STRIDE_COUNT; + + bootstream_size_pages = (size + (nand_writesize - 1)) / + nand_writesize; + + fw1_start_page = 2 * bcb_size_bytes / nand_writesize; + fw2_start_page = (2 * bcb_size_bytes + MAX_BOOTSTREAM_SIZE) / + nand_writesize; + + fcb->firmware1_starting_sector = fw1_start_page; + fcb->firmware2_starting_sector = fw2_start_page; + fcb->sectors_in_firmware1 = bootstream_size_pages; + fcb->sectors_in_firmware2 = bootstream_size_pages; + + fcb->dbbt_search_area_start_address = STRIDE_PAGES * STRIDE_COUNT; + + return fcb; + +err: + free(fcb); + return NULL; +} + +static struct mx28_nand_dbbt *mx28_nand_get_dbbt(void) +{ + struct mx28_nand_dbbt *dbbt; + + dbbt = malloc(nand_writesize); + if (!dbbt) { + printf("MX28 NAND: Unable to allocate DBBT\n"); + return NULL; + } + + memset(dbbt, 0, nand_writesize); + + dbbt->fingerprint = 0x54424244; + dbbt->version = 0x1; + + return dbbt; +} + +static inline uint8_t mx28_nand_parity_13_8(const uint8_t b) +{ + uint32_t parity = 0, tmp; + + tmp = ((b >> 6) ^ (b >> 5) ^ (b >> 3) ^ (b >> 2)) & 1; + parity |= tmp << 0; + + tmp = ((b >> 7) ^ (b >> 5) ^ (b >> 4) ^ (b >> 2) ^ (b >> 1)) & 1; + parity |= tmp << 1; + + tmp = ((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 1) ^ (b >> 0)) & 1; + parity |= tmp << 2; + + tmp = ((b >> 7) ^ (b >> 4) ^ (b >> 3) ^ (b >> 0)) & 1; + parity |= tmp << 3; + + tmp = ((b >> 6) ^ (b >> 4) ^ (b >> 3) ^ + (b >> 2) ^ (b >> 1) ^ (b >> 0)) & 1; + parity |= tmp << 4; + + return parity; +} + +static uint8_t *mx28_nand_fcb_block(struct mx28_nand_fcb *fcb) +{ + uint8_t *block; + uint8_t *ecc; + int i; + + block = malloc(nand_writesize + nand_oobsize); + if (!block) { + printf("MX28 NAND: Unable to allocate FCB block\n"); + return NULL; + } + + memset(block, 0, nand_writesize + nand_oobsize); + + /* Update the FCB checksum */ + fcb->checksum = mx28_nand_block_csum(((uint8_t *)fcb) + 4, 508); + + /* Figure 12-11. in iMX28RM, rev. 1, says FCB is at offset 12 */ + memcpy(block + 12, fcb, sizeof(struct mx28_nand_fcb)); + + /* ECC is at offset 12 + 512 */ + ecc = block + 12 + 512; + + /* Compute the ECC parity */ + for (i = 0; i < sizeof(struct mx28_nand_fcb); i++) + ecc[i] = mx28_nand_parity_13_8(block[i + 12]); + + return block; +} + +static int mx28_nand_write_fcb(struct mx28_nand_fcb *fcb, uint8_t *buf) +{ + uint32_t offset; + uint8_t *fcbblock; + int ret = 0; + int i; + + fcbblock = mx28_nand_fcb_block(fcb); + if (!fcbblock) + return -1; + + for (i = 0; i < STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) { + offset = i * nand_writesize; + memcpy(buf + offset, fcbblock, nand_writesize + nand_oobsize); + /* Mark the NAND page is OK. */ + buf[offset + nand_writesize] = 0xff; + } + + free(fcbblock); + return ret; +} + +static int mx28_nand_write_dbbt(struct mx28_nand_dbbt *dbbt, uint8_t *buf) +{ + uint32_t offset; + int i = STRIDE_PAGES * STRIDE_COUNT; + + for (; i < 2 * STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) { + offset = i * nand_writesize; + memcpy(buf + offset, dbbt, sizeof(struct mx28_nand_dbbt)); + } + + return 0; +} + +static int mx28_nand_write_firmware(struct mx28_nand_fcb *fcb, int infd, + uint8_t *buf) +{ + int ret; + off_t size; + uint32_t offset1, offset2; + + size = lseek(infd, 0, SEEK_END); + lseek(infd, 0, SEEK_SET); + + offset1 = fcb->firmware1_starting_sector * nand_writesize; + offset2 = fcb->firmware2_starting_sector * nand_writesize; + + ret = read(infd, buf + offset1, size); + if (ret != size) + return -1; + + memcpy(buf + offset2, buf + offset1, size); + + return 0; +} + +static void usage(void) +{ + printf( + "Usage: mxsboot [ops] <type> <infile> <outfile>\n" + "Augment BootStream file with a proper header for i.MX28 boot\n" + "\n" + " <type> type of image:\n" + " \"nand\" for NAND image\n" + " \"sd\" for SD image\n" + " <infile> input file, the u-boot.sb bootstream\n" + " <outfile> output file, the bootable image\n" + "\n"); + printf( + "For NAND boot, these options are accepted:\n" + " -w <size> NAND page size\n" + " -o <size> NAND OOB size\n" + " -e <size> NAND erase size\n" + "\n" + "For SD boot, these options are accepted:\n" + " -p <sector> Sector where the SGTL partition starts\n" + ); +} + +static int mx28_create_nand_image(int infd, int outfd) +{ + struct mx28_nand_fcb *fcb; + struct mx28_nand_dbbt *dbbt; + int ret = -1; + uint8_t *buf; + int size; + ssize_t wr_size; + + size = nand_writesize * 512 + 2 * MAX_BOOTSTREAM_SIZE; + + buf = malloc(size); + if (!buf) { + printf("Can not allocate output buffer of %d bytes\n", size); + goto err0; + } + + memset(buf, 0, size); + + fcb = mx28_nand_get_fcb(MAX_BOOTSTREAM_SIZE); + if (!fcb) { + printf("Unable to compile FCB\n"); + goto err1; + } + + dbbt = mx28_nand_get_dbbt(); + if (!dbbt) { + printf("Unable to compile DBBT\n"); + goto err2; + } + + ret = mx28_nand_write_fcb(fcb, buf); + if (ret) { + printf("Unable to write FCB to buffer\n"); + goto err3; + } + + ret = mx28_nand_write_dbbt(dbbt, buf); + if (ret) { + printf("Unable to write DBBT to buffer\n"); + goto err3; + } + + ret = mx28_nand_write_firmware(fcb, infd, buf); + if (ret) { + printf("Unable to write firmware to buffer\n"); + goto err3; + } + + wr_size = write(outfd, buf, size); + if (wr_size != size) { + ret = -1; + goto err3; + } + + ret = 0; + +err3: + free(dbbt); +err2: + free(fcb); +err1: + free(buf); +err0: + return ret; +} + +static int mx28_create_sd_image(int infd, int outfd) +{ + int ret = -1; + uint32_t *buf; + int size; + off_t fsize; + ssize_t wr_size; + struct mx28_sd_config_block *cb; + + fsize = lseek(infd, 0, SEEK_END); + lseek(infd, 0, SEEK_SET); + size = fsize + 4 * 512; + + buf = malloc(size); + if (!buf) { + printf("Can not allocate output buffer of %d bytes\n", size); + goto err0; + } + + ret = read(infd, (uint8_t *)buf + 4 * 512, fsize); + if (ret != fsize) { + ret = -1; + goto err1; + } + + cb = (struct mx28_sd_config_block *)buf; + + cb->signature = 0x00112233; + cb->primary_boot_tag = 0x1; + cb->secondary_boot_tag = 0x1; + cb->num_copies = 1; + cb->drv_info[0].chip_num = 0x0; + cb->drv_info[0].drive_type = 0x0; + cb->drv_info[0].tag = 0x1; + cb->drv_info[0].first_sector_number = sd_sector + 4; + cb->drv_info[0].sector_count = (size - 4) / 512; + + wr_size = write(outfd, buf, size); + if (wr_size != size) { + ret = -1; + goto err1; + } + + ret = 0; + +err1: + free(buf); +err0: + return ret; +} + +static int parse_ops(int argc, char **argv) +{ + int i; + int tmp; + char *end; + enum param { + PARAM_WRITE, + PARAM_OOB, + PARAM_ERASE, + PARAM_PART, + PARAM_SD, + PARAM_NAND + }; + int type; + + if (argc < 4) + return -1; + + for (i = 1; i < argc; i++) { + if (!strncmp(argv[i], "-w", 2)) + type = PARAM_WRITE; + else if (!strncmp(argv[i], "-o", 2)) + type = PARAM_OOB; + else if (!strncmp(argv[i], "-e", 2)) + type = PARAM_ERASE; + else if (!strncmp(argv[i], "-p", 2)) + type = PARAM_PART; + else /* SD/MMC */ + break; + + tmp = strtol(argv[++i], &end, 10); + if (tmp % 2) + return -1; + if (tmp <= 0) + return -1; + + if (type == PARAM_WRITE) + nand_writesize = tmp; + if (type == PARAM_OOB) + nand_oobsize = tmp; + if (type == PARAM_ERASE) + nand_erasesize = tmp; + if (type == PARAM_PART) + sd_sector = tmp; + } + + if (strcmp(argv[i], "sd") && strcmp(argv[i], "nand")) + return -1; + + if (i + 3 != argc) + return -1; + + return i; +} + +int main(int argc, char **argv) +{ + int infd, outfd; + int ret = 0; + int offset; + + offset = parse_ops(argc, argv); + if (offset < 0) { + usage(); + ret = 1; + goto err1; + } + + infd = open(argv[offset + 1], O_RDONLY); + if (infd < 0) { + printf("Input BootStream file can not be opened\n"); + ret = 2; + goto err1; + } + + outfd = open(argv[offset + 2], O_CREAT | O_TRUNC | O_WRONLY, + S_IRUSR | S_IWUSR); + if (outfd < 0) { + printf("Output file can not be created\n"); + ret = 3; + goto err2; + } + + if (!strcmp(argv[offset], "sd")) + ret = mx28_create_sd_image(infd, outfd); + else if (!strcmp(argv[offset], "nand")) + ret = mx28_create_nand_image(infd, outfd); + + close(outfd); +err2: + close(infd); +err1: + return ret; +} diff --git a/qemu/roms/u-boot/tools/mxsimage.c b/qemu/roms/u-boot/tools/mxsimage.c new file mode 100644 index 000000000..045b35a39 --- /dev/null +++ b/qemu/roms/u-boot/tools/mxsimage.c @@ -0,0 +1,2348 @@ +/* + * Freescale i.MX23/i.MX28 SB image generator + * + * Copyright (C) 2012-2013 Marek Vasut <marex@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifdef CONFIG_MXS + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> + +#include <openssl/evp.h> + +#include "imagetool.h" +#include "mxsimage.h" +#include <image.h> + + +/* + * DCD block + * |-Write to address command block + * | 0xf00 == 0xf33d + * | 0xba2 == 0xb33f + * |-ORR address with mask command block + * | 0xf00 |= 0x1337 + * |-Write to address command block + * | 0xba2 == 0xd00d + * : + */ +#define SB_HAB_DCD_WRITE 0xccUL +#define SB_HAB_DCD_CHECK 0xcfUL +#define SB_HAB_DCD_NOOP 0xc0UL +#define SB_HAB_DCD_MASK_BIT (1 << 3) +#define SB_HAB_DCD_SET_BIT (1 << 4) + +/* Addr.n = Value.n */ +#define SB_DCD_WRITE \ + (SB_HAB_DCD_WRITE << 24) +/* Addr.n &= ~Value.n */ +#define SB_DCD_ANDC \ + ((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT) +/* Addr.n |= Value.n */ +#define SB_DCD_ORR \ + ((SB_HAB_DCD_WRITE << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT) +/* (Addr.n & Value.n) == 0 */ +#define SB_DCD_CHK_EQZ \ + (SB_HAB_DCD_CHECK << 24) +/* (Addr.n & Value.n) == Value.n */ +#define SB_DCD_CHK_EQ \ + ((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT) +/* (Addr.n & Value.n) != Value.n */ +#define SB_DCD_CHK_NEQ \ + ((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_MASK_BIT) +/* (Addr.n & Value.n) != 0 */ +#define SB_DCD_CHK_NEZ \ + ((SB_HAB_DCD_CHECK << 24) | SB_HAB_DCD_SET_BIT | SB_HAB_DCD_MASK_BIT) +/* NOP */ +#define SB_DCD_NOOP \ + (SB_HAB_DCD_NOOP << 24) + +struct sb_dcd_ctx { + struct sb_dcd_ctx *dcd; + + uint32_t id; + + /* The DCD block. */ + uint32_t *payload; + /* Size of the whole DCD block. */ + uint32_t size; + + /* Pointer to previous DCD command block. */ + uint32_t *prev_dcd_head; +}; + +/* + * IMAGE + * |-SECTION + * | |-CMD + * | |-CMD + * | `-CMD + * |-SECTION + * | |-CMD + * : : + */ +struct sb_cmd_list { + char *cmd; + size_t len; + unsigned int lineno; +}; + +struct sb_cmd_ctx { + uint32_t size; + + struct sb_cmd_ctx *cmd; + + uint8_t *data; + uint32_t length; + + struct sb_command payload; + struct sb_command c_payload; +}; + +struct sb_section_ctx { + uint32_t size; + + /* Section flags */ + unsigned int boot:1; + + struct sb_section_ctx *sect; + + struct sb_cmd_ctx *cmd_head; + struct sb_cmd_ctx *cmd_tail; + + struct sb_sections_header payload; +}; + +struct sb_image_ctx { + unsigned int in_section:1; + unsigned int in_dcd:1; + /* Image configuration */ + unsigned int verbose_boot:1; + unsigned int silent_dump:1; + char *input_filename; + char *output_filename; + char *cfg_filename; + uint8_t image_key[16]; + + /* Number of section in the image */ + unsigned int sect_count; + /* Bootable section */ + unsigned int sect_boot; + unsigned int sect_boot_found:1; + + struct sb_section_ctx *sect_head; + struct sb_section_ctx *sect_tail; + + struct sb_dcd_ctx *dcd_head; + struct sb_dcd_ctx *dcd_tail; + + EVP_CIPHER_CTX cipher_ctx; + EVP_MD_CTX md_ctx; + uint8_t digest[32]; + struct sb_key_dictionary_key sb_dict_key; + + struct sb_boot_image_header payload; +}; + +/* + * Instruction semantics: + * NOOP + * TAG [LAST] + * LOAD address file + * LOAD IVT address IVT_entry_point + * FILL address pattern length + * JUMP [HAB] address [r0_arg] + * CALL [HAB] address [r0_arg] + * MODE mode + * For i.MX23, mode = USB/I2C/SPI1_FLASH/SPI2_FLASH/NAND_BCH + * JTAG/SPI3_EEPROM/SD_SSP0/SD_SSP1 + * For i.MX28, mode = USB/I2C/SPI2_FLASH/SPI3_FLASH/NAND_BCH + * JTAG/SPI2_EEPROM/SD_SSP0/SD_SSP1 + */ + +/* + * AES libcrypto + */ +static int sb_aes_init(struct sb_image_ctx *ictx, uint8_t *iv, int enc) +{ + EVP_CIPHER_CTX *ctx = &ictx->cipher_ctx; + int ret; + + /* If there is no init vector, init vector is all zeroes. */ + if (!iv) + iv = ictx->image_key; + + EVP_CIPHER_CTX_init(ctx); + ret = EVP_CipherInit(ctx, EVP_aes_128_cbc(), ictx->image_key, iv, enc); + if (ret == 1) + EVP_CIPHER_CTX_set_padding(ctx, 0); + return ret; +} + +static int sb_aes_crypt(struct sb_image_ctx *ictx, uint8_t *in_data, + uint8_t *out_data, int in_len) +{ + EVP_CIPHER_CTX *ctx = &ictx->cipher_ctx; + int ret, outlen; + uint8_t *outbuf; + + outbuf = malloc(in_len); + if (!outbuf) + return -ENOMEM; + memset(outbuf, 0, sizeof(in_len)); + + ret = EVP_CipherUpdate(ctx, outbuf, &outlen, in_data, in_len); + if (!ret) { + ret = -EINVAL; + goto err; + } + + if (out_data) + memcpy(out_data, outbuf, outlen); + +err: + free(outbuf); + return ret; +} + +static int sb_aes_deinit(EVP_CIPHER_CTX *ctx) +{ + return EVP_CIPHER_CTX_cleanup(ctx); +} + +static int sb_aes_reinit(struct sb_image_ctx *ictx, int enc) +{ + int ret; + EVP_CIPHER_CTX *ctx = &ictx->cipher_ctx; + struct sb_boot_image_header *sb_header = &ictx->payload; + uint8_t *iv = sb_header->iv; + + ret = sb_aes_deinit(ctx); + if (!ret) + return ret; + return sb_aes_init(ictx, iv, enc); +} + +/* + * CRC32 + */ +static uint32_t crc32(uint8_t *data, uint32_t len) +{ + const uint32_t poly = 0x04c11db7; + uint32_t crc32 = 0xffffffff; + unsigned int byte, bit; + + for (byte = 0; byte < len; byte++) { + crc32 ^= data[byte] << 24; + + for (bit = 8; bit > 0; bit--) { + if (crc32 & (1UL << 31)) + crc32 = (crc32 << 1) ^ poly; + else + crc32 = (crc32 << 1); + } + } + + return crc32; +} + +/* + * Debug + */ +static void soprintf(struct sb_image_ctx *ictx, const char *fmt, ...) +{ + va_list ap; + + if (ictx->silent_dump) + return; + + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); +} + +/* + * Code + */ +static time_t sb_get_timestamp(void) +{ + struct tm time_2000 = { + .tm_yday = 1, /* Jan. 1st */ + .tm_year = 100, /* 2000 */ + }; + time_t seconds_to_2000 = mktime(&time_2000); + time_t seconds_to_now = time(NULL); + + return seconds_to_now - seconds_to_2000; +} + +static int sb_get_time(time_t time, struct tm *tm) +{ + struct tm time_2000 = { + .tm_yday = 1, /* Jan. 1st */ + .tm_year = 0, /* 1900 */ + }; + const time_t seconds_to_2000 = mktime(&time_2000); + const time_t seconds_to_now = seconds_to_2000 + time; + struct tm *ret; + ret = gmtime_r(&seconds_to_now, tm); + return ret ? 0 : -EINVAL; +} + +static void sb_encrypt_sb_header(struct sb_image_ctx *ictx) +{ + EVP_MD_CTX *md_ctx = &ictx->md_ctx; + struct sb_boot_image_header *sb_header = &ictx->payload; + uint8_t *sb_header_ptr = (uint8_t *)sb_header; + + /* Encrypt the header, compute the digest. */ + sb_aes_crypt(ictx, sb_header_ptr, NULL, sizeof(*sb_header)); + EVP_DigestUpdate(md_ctx, sb_header_ptr, sizeof(*sb_header)); +} + +static void sb_encrypt_sb_sections_header(struct sb_image_ctx *ictx) +{ + EVP_MD_CTX *md_ctx = &ictx->md_ctx; + struct sb_section_ctx *sctx = ictx->sect_head; + struct sb_sections_header *shdr; + uint8_t *sb_sections_header_ptr; + const int size = sizeof(*shdr); + + while (sctx) { + shdr = &sctx->payload; + sb_sections_header_ptr = (uint8_t *)shdr; + + sb_aes_crypt(ictx, sb_sections_header_ptr, + ictx->sb_dict_key.cbc_mac, size); + EVP_DigestUpdate(md_ctx, sb_sections_header_ptr, size); + + sctx = sctx->sect; + }; +} + +static void sb_encrypt_key_dictionary_key(struct sb_image_ctx *ictx) +{ + EVP_MD_CTX *md_ctx = &ictx->md_ctx; + + sb_aes_crypt(ictx, ictx->image_key, ictx->sb_dict_key.key, + sizeof(ictx->sb_dict_key.key)); + EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key)); +} + +static void sb_decrypt_key_dictionary_key(struct sb_image_ctx *ictx) +{ + EVP_MD_CTX *md_ctx = &ictx->md_ctx; + + EVP_DigestUpdate(md_ctx, &ictx->sb_dict_key, sizeof(ictx->sb_dict_key)); + sb_aes_crypt(ictx, ictx->sb_dict_key.key, ictx->image_key, + sizeof(ictx->sb_dict_key.key)); +} + +static void sb_encrypt_tag(struct sb_image_ctx *ictx, + struct sb_cmd_ctx *cctx) +{ + EVP_MD_CTX *md_ctx = &ictx->md_ctx; + struct sb_command *cmd = &cctx->payload; + + sb_aes_crypt(ictx, (uint8_t *)cmd, + (uint8_t *)&cctx->c_payload, sizeof(*cmd)); + EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd)); +} + +static int sb_encrypt_image(struct sb_image_ctx *ictx) +{ + /* Start image-wide crypto. */ + EVP_MD_CTX_init(&ictx->md_ctx); + EVP_DigestInit(&ictx->md_ctx, EVP_sha1()); + + /* + * SB image header. + */ + sb_aes_init(ictx, NULL, 1); + sb_encrypt_sb_header(ictx); + + /* + * SB sections header. + */ + sb_encrypt_sb_sections_header(ictx); + + /* + * Key dictionary. + */ + sb_aes_reinit(ictx, 1); + sb_encrypt_key_dictionary_key(ictx); + + /* + * Section tags. + */ + struct sb_cmd_ctx *cctx; + struct sb_command *ccmd; + struct sb_section_ctx *sctx = ictx->sect_head; + + while (sctx) { + cctx = sctx->cmd_head; + + sb_aes_reinit(ictx, 1); + + while (cctx) { + ccmd = &cctx->payload; + + sb_encrypt_tag(ictx, cctx); + + if (ccmd->header.tag == ROM_TAG_CMD) { + sb_aes_reinit(ictx, 1); + } else if (ccmd->header.tag == ROM_LOAD_CMD) { + sb_aes_crypt(ictx, cctx->data, cctx->data, + cctx->length); + EVP_DigestUpdate(&ictx->md_ctx, cctx->data, + cctx->length); + } + + cctx = cctx->cmd; + } + + sctx = sctx->sect; + }; + + /* + * Dump the SHA1 of the whole image. + */ + sb_aes_reinit(ictx, 1); + + EVP_DigestFinal(&ictx->md_ctx, ictx->digest, NULL); + sb_aes_crypt(ictx, ictx->digest, ictx->digest, sizeof(ictx->digest)); + + /* Stop the encryption session. */ + sb_aes_deinit(&ictx->cipher_ctx); + + return 0; +} + +static int sb_load_file(struct sb_cmd_ctx *cctx, char *filename) +{ + long real_size, roundup_size; + uint8_t *data; + long ret; + unsigned long size; + FILE *fp; + + if (!filename) { + fprintf(stderr, "ERR: Missing filename!\n"); + return -EINVAL; + } + + fp = fopen(filename, "r"); + if (!fp) + goto err_open; + + ret = fseek(fp, 0, SEEK_END); + if (ret < 0) + goto err_file; + + real_size = ftell(fp); + if (real_size < 0) + goto err_file; + + ret = fseek(fp, 0, SEEK_SET); + if (ret < 0) + goto err_file; + + roundup_size = roundup(real_size, SB_BLOCK_SIZE); + data = calloc(1, roundup_size); + if (!data) + goto err_file; + + size = fread(data, 1, real_size, fp); + if (size != (unsigned long)real_size) + goto err_alloc; + + cctx->data = data; + cctx->length = roundup_size; + + fclose(fp); + return 0; + +err_alloc: + free(data); +err_file: + fclose(fp); +err_open: + fprintf(stderr, "ERR: Failed to load file \"%s\"\n", filename); + return -EINVAL; +} + +static uint8_t sb_command_checksum(struct sb_command *inst) +{ + uint8_t *inst_ptr = (uint8_t *)inst; + uint8_t csum = 0; + unsigned int i; + + for (i = 0; i < sizeof(struct sb_command); i++) + csum += inst_ptr[i]; + + return csum; +} + +static int sb_token_to_long(char *tok, uint32_t *rid) +{ + char *endptr; + unsigned long id; + + if (tok[0] != '0' || tok[1] != 'x') { + fprintf(stderr, "ERR: Invalid hexadecimal number!\n"); + return -EINVAL; + } + + tok += 2; + + errno = 0; + id = strtoul(tok, &endptr, 16); + if ((errno == ERANGE && id == ULONG_MAX) || (errno != 0 && id == 0)) { + fprintf(stderr, "ERR: Value can't be decoded!\n"); + return -EINVAL; + } + + /* Check for 32-bit overflow. */ + if (id > 0xffffffff) { + fprintf(stderr, "ERR: Value too big!\n"); + return -EINVAL; + } + + if (endptr == tok) { + fprintf(stderr, "ERR: Deformed value!\n"); + return -EINVAL; + } + + *rid = (uint32_t)id; + return 0; +} + +static int sb_grow_dcd(struct sb_dcd_ctx *dctx, unsigned int inc_size) +{ + uint32_t *tmp; + + if (!inc_size) + return 0; + + dctx->size += inc_size; + tmp = realloc(dctx->payload, dctx->size); + if (!tmp) + return -ENOMEM; + + dctx->payload = tmp; + + /* Assemble and update the HAB DCD header. */ + dctx->payload[0] = htonl((SB_HAB_DCD_TAG << 24) | + (dctx->size << 8) | + SB_HAB_VERSION); + + return 0; +} + +static int sb_build_dcd(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd) +{ + struct sb_dcd_ctx *dctx; + + char *tok; + uint32_t id; + int ret; + + dctx = calloc(1, sizeof(*dctx)); + if (!dctx) + return -ENOMEM; + + ret = sb_grow_dcd(dctx, 4); + if (ret) + goto err_dcd; + + /* Read DCD block number. */ + tok = strtok(cmd->cmd, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: DCD block without number!\n", + cmd->lineno); + ret = -EINVAL; + goto err_dcd; + } + + /* Parse the DCD block number. */ + ret = sb_token_to_long(tok, &id); + if (ret) { + fprintf(stderr, "#%i ERR: Malformed DCD block number!\n", + cmd->lineno); + goto err_dcd; + } + + dctx->id = id; + + /* + * The DCD block is now constructed. Append it to the list. + * WARNING: The DCD size is still not computed and will be + * updated while parsing it's commands. + */ + if (!ictx->dcd_head) { + ictx->dcd_head = dctx; + ictx->dcd_tail = dctx; + } else { + ictx->dcd_tail->dcd = dctx; + ictx->dcd_tail = dctx; + } + + return 0; + +err_dcd: + free(dctx->payload); + free(dctx); + return ret; +} + +static int sb_build_dcd_block(struct sb_image_ctx *ictx, + struct sb_cmd_list *cmd, + uint32_t type) +{ + char *tok; + uint32_t address, value, length; + int ret; + + struct sb_dcd_ctx *dctx = ictx->dcd_tail; + uint32_t *dcd; + + if (dctx->prev_dcd_head && (type != SB_DCD_NOOP) && + ((dctx->prev_dcd_head[0] & 0xff0000ff) == type)) { + /* Same instruction as before, just append it. */ + ret = sb_grow_dcd(dctx, 8); + if (ret) + return ret; + } else if (type == SB_DCD_NOOP) { + ret = sb_grow_dcd(dctx, 4); + if (ret) + return ret; + + /* Update DCD command block pointer. */ + dctx->prev_dcd_head = dctx->payload + + dctx->size / sizeof(*dctx->payload) - 1; + + /* NOOP has only 4 bytes and no payload. */ + goto noop; + } else { + /* + * Either a different instruction block started now + * or this is the first instruction block. + */ + ret = sb_grow_dcd(dctx, 12); + if (ret) + return ret; + + /* Update DCD command block pointer. */ + dctx->prev_dcd_head = dctx->payload + + dctx->size / sizeof(*dctx->payload) - 3; + } + + dcd = dctx->payload + dctx->size / sizeof(*dctx->payload) - 2; + + /* + * Prepare the command. + */ + tok = strtok(cmd->cmd, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Missing DCD address!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + + /* Read DCD destination address. */ + ret = sb_token_to_long(tok, &address); + if (ret) { + fprintf(stderr, "#%i ERR: Incorrect DCD address!\n", + cmd->lineno); + goto err; + } + + tok = strtok(NULL, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Missing DCD value!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + + /* Read DCD operation value. */ + ret = sb_token_to_long(tok, &value); + if (ret) { + fprintf(stderr, "#%i ERR: Incorrect DCD value!\n", + cmd->lineno); + goto err; + } + + /* Fill in the new DCD entry. */ + dcd[0] = htonl(address); + dcd[1] = htonl(value); + +noop: + /* Update the DCD command block. */ + length = dctx->size - + ((dctx->prev_dcd_head - dctx->payload) * + sizeof(*dctx->payload)); + dctx->prev_dcd_head[0] = htonl(type | (length << 8)); + +err: + return ret; +} + +static int sb_build_section(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd) +{ + struct sb_section_ctx *sctx; + struct sb_sections_header *shdr; + char *tok; + uint32_t bootable = 0; + uint32_t id; + int ret; + + sctx = calloc(1, sizeof(*sctx)); + if (!sctx) + return -ENOMEM; + + /* Read section number. */ + tok = strtok(cmd->cmd, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Section without number!\n", + cmd->lineno); + ret = -EINVAL; + goto err_sect; + } + + /* Parse the section number. */ + ret = sb_token_to_long(tok, &id); + if (ret) { + fprintf(stderr, "#%i ERR: Malformed section number!\n", + cmd->lineno); + goto err_sect; + } + + /* Read section's BOOTABLE flag. */ + tok = strtok(NULL, " "); + if (tok && (strlen(tok) == 8) && !strncmp(tok, "BOOTABLE", 8)) + bootable = SB_SECTION_FLAG_BOOTABLE; + + sctx->boot = bootable; + + shdr = &sctx->payload; + shdr->section_number = id; + shdr->section_flags = bootable; + + /* + * The section is now constructed. Append it to the list. + * WARNING: The section size is still not computed and will + * be updated while parsing it's commands. + */ + ictx->sect_count++; + + /* Mark that this section is bootable one. */ + if (bootable) { + if (ictx->sect_boot_found) { + fprintf(stderr, + "#%i WARN: Multiple bootable section!\n", + cmd->lineno); + } else { + ictx->sect_boot = id; + ictx->sect_boot_found = 1; + } + } + + if (!ictx->sect_head) { + ictx->sect_head = sctx; + ictx->sect_tail = sctx; + } else { + ictx->sect_tail->sect = sctx; + ictx->sect_tail = sctx; + } + + return 0; + +err_sect: + free(sctx); + return ret; +} + +static int sb_build_command_nop(struct sb_image_ctx *ictx) +{ + struct sb_section_ctx *sctx = ictx->sect_tail; + struct sb_cmd_ctx *cctx; + struct sb_command *ccmd; + + cctx = calloc(1, sizeof(*cctx)); + if (!cctx) + return -ENOMEM; + + ccmd = &cctx->payload; + + /* + * Construct the command. + */ + ccmd->header.checksum = 0x5a; + ccmd->header.tag = ROM_NOP_CMD; + + cctx->size = sizeof(*ccmd); + + /* + * Append the command to the last section. + */ + if (!sctx->cmd_head) { + sctx->cmd_head = cctx; + sctx->cmd_tail = cctx; + } else { + sctx->cmd_tail->cmd = cctx; + sctx->cmd_tail = cctx; + } + + return 0; +} + +static int sb_build_command_tag(struct sb_image_ctx *ictx, + struct sb_cmd_list *cmd) +{ + struct sb_section_ctx *sctx = ictx->sect_tail; + struct sb_cmd_ctx *cctx; + struct sb_command *ccmd; + char *tok; + + cctx = calloc(1, sizeof(*cctx)); + if (!cctx) + return -ENOMEM; + + ccmd = &cctx->payload; + + /* + * Prepare the command. + */ + /* Check for the LAST keyword. */ + tok = strtok(cmd->cmd, " "); + if (tok && !strcmp(tok, "LAST")) + ccmd->header.flags = ROM_TAG_CMD_FLAG_ROM_LAST_TAG; + + /* + * Construct the command. + */ + ccmd->header.checksum = 0x5a; + ccmd->header.tag = ROM_TAG_CMD; + + cctx->size = sizeof(*ccmd); + + /* + * Append the command to the last section. + */ + if (!sctx->cmd_head) { + sctx->cmd_head = cctx; + sctx->cmd_tail = cctx; + } else { + sctx->cmd_tail->cmd = cctx; + sctx->cmd_tail = cctx; + } + + return 0; +} + +static int sb_build_command_load(struct sb_image_ctx *ictx, + struct sb_cmd_list *cmd) +{ + struct sb_section_ctx *sctx = ictx->sect_tail; + struct sb_cmd_ctx *cctx; + struct sb_command *ccmd; + char *tok; + int ret, is_ivt = 0, is_dcd = 0; + uint32_t dest, dcd = 0; + + cctx = calloc(1, sizeof(*cctx)); + if (!cctx) + return -ENOMEM; + + ccmd = &cctx->payload; + + /* + * Prepare the command. + */ + tok = strtok(cmd->cmd, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Missing LOAD address or 'IVT'!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + + /* Check for "IVT" flag. */ + if (!strcmp(tok, "IVT")) + is_ivt = 1; + if (!strcmp(tok, "DCD")) + is_dcd = 1; + if (is_ivt || is_dcd) { + tok = strtok(NULL, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Missing LOAD address!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + } + + /* Read load destination address. */ + ret = sb_token_to_long(tok, &dest); + if (ret) { + fprintf(stderr, "#%i ERR: Incorrect LOAD address!\n", + cmd->lineno); + goto err; + } + + /* Read filename or IVT entrypoint or DCD block ID. */ + tok = strtok(NULL, " "); + if (!tok) { + fprintf(stderr, + "#%i ERR: Missing LOAD filename or IVT ep or DCD block ID!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + + if (is_ivt) { + /* Handle IVT. */ + struct sb_ivt_header *ivt; + uint32_t ivtep; + ret = sb_token_to_long(tok, &ivtep); + + if (ret) { + fprintf(stderr, + "#%i ERR: Incorrect IVT entry point!\n", + cmd->lineno); + goto err; + } + + ivt = calloc(1, sizeof(*ivt)); + if (!ivt) { + ret = -ENOMEM; + goto err; + } + + ivt->header = sb_hab_ivt_header(); + ivt->entry = ivtep; + ivt->self = dest; + + cctx->data = (uint8_t *)ivt; + cctx->length = sizeof(*ivt); + } else if (is_dcd) { + struct sb_dcd_ctx *dctx = ictx->dcd_head; + uint32_t dcdid; + uint8_t *payload; + uint32_t asize; + ret = sb_token_to_long(tok, &dcdid); + + if (ret) { + fprintf(stderr, + "#%i ERR: Incorrect DCD block ID!\n", + cmd->lineno); + goto err; + } + + while (dctx) { + if (dctx->id == dcdid) + break; + dctx = dctx->dcd; + } + + if (!dctx) { + fprintf(stderr, "#%i ERR: DCD block %08x not found!\n", + cmd->lineno, dcdid); + goto err; + } + + asize = roundup(dctx->size, SB_BLOCK_SIZE); + payload = calloc(1, asize); + if (!payload) { + ret = -ENOMEM; + goto err; + } + + memcpy(payload, dctx->payload, dctx->size); + + cctx->data = payload; + cctx->length = asize; + + /* Set the Load DCD flag. */ + dcd = ROM_LOAD_CMD_FLAG_DCD_LOAD; + } else { + /* Regular LOAD of a file. */ + ret = sb_load_file(cctx, tok); + if (ret) { + fprintf(stderr, "#%i ERR: Cannot load '%s'!\n", + cmd->lineno, tok); + goto err; + } + } + + if (cctx->length & (SB_BLOCK_SIZE - 1)) { + fprintf(stderr, "#%i ERR: Unaligned payload!\n", + cmd->lineno); + } + + /* + * Construct the command. + */ + ccmd->header.checksum = 0x5a; + ccmd->header.tag = ROM_LOAD_CMD; + ccmd->header.flags = dcd; + + ccmd->load.address = dest; + ccmd->load.count = cctx->length; + ccmd->load.crc32 = crc32(cctx->data, cctx->length); + + cctx->size = sizeof(*ccmd) + cctx->length; + + /* + * Append the command to the last section. + */ + if (!sctx->cmd_head) { + sctx->cmd_head = cctx; + sctx->cmd_tail = cctx; + } else { + sctx->cmd_tail->cmd = cctx; + sctx->cmd_tail = cctx; + } + + return 0; + +err: + free(cctx); + return ret; +} + +static int sb_build_command_fill(struct sb_image_ctx *ictx, + struct sb_cmd_list *cmd) +{ + struct sb_section_ctx *sctx = ictx->sect_tail; + struct sb_cmd_ctx *cctx; + struct sb_command *ccmd; + char *tok; + uint32_t address, pattern, length; + int ret; + + cctx = calloc(1, sizeof(*cctx)); + if (!cctx) + return -ENOMEM; + + ccmd = &cctx->payload; + + /* + * Prepare the command. + */ + tok = strtok(cmd->cmd, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Missing FILL address!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + + /* Read fill destination address. */ + ret = sb_token_to_long(tok, &address); + if (ret) { + fprintf(stderr, "#%i ERR: Incorrect FILL address!\n", + cmd->lineno); + goto err; + } + + tok = strtok(NULL, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Missing FILL pattern!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + + /* Read fill pattern address. */ + ret = sb_token_to_long(tok, &pattern); + if (ret) { + fprintf(stderr, "#%i ERR: Incorrect FILL pattern!\n", + cmd->lineno); + goto err; + } + + tok = strtok(NULL, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Missing FILL length!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + + /* Read fill pattern address. */ + ret = sb_token_to_long(tok, &length); + if (ret) { + fprintf(stderr, "#%i ERR: Incorrect FILL length!\n", + cmd->lineno); + goto err; + } + + /* + * Construct the command. + */ + ccmd->header.checksum = 0x5a; + ccmd->header.tag = ROM_FILL_CMD; + + ccmd->fill.address = address; + ccmd->fill.count = length; + ccmd->fill.pattern = pattern; + + cctx->size = sizeof(*ccmd); + + /* + * Append the command to the last section. + */ + if (!sctx->cmd_head) { + sctx->cmd_head = cctx; + sctx->cmd_tail = cctx; + } else { + sctx->cmd_tail->cmd = cctx; + sctx->cmd_tail = cctx; + } + + return 0; + +err: + free(cctx); + return ret; +} + +static int sb_build_command_jump_call(struct sb_image_ctx *ictx, + struct sb_cmd_list *cmd, + unsigned int is_call) +{ + struct sb_section_ctx *sctx = ictx->sect_tail; + struct sb_cmd_ctx *cctx; + struct sb_command *ccmd; + char *tok; + uint32_t dest, arg = 0x0; + uint32_t hab = 0; + int ret; + const char *cmdname = is_call ? "CALL" : "JUMP"; + + cctx = calloc(1, sizeof(*cctx)); + if (!cctx) + return -ENOMEM; + + ccmd = &cctx->payload; + + /* + * Prepare the command. + */ + tok = strtok(cmd->cmd, " "); + if (!tok) { + fprintf(stderr, + "#%i ERR: Missing %s address or 'HAB'!\n", + cmd->lineno, cmdname); + ret = -EINVAL; + goto err; + } + + /* Check for "HAB" flag. */ + if (!strcmp(tok, "HAB")) { + hab = is_call ? ROM_CALL_CMD_FLAG_HAB : ROM_JUMP_CMD_FLAG_HAB; + tok = strtok(NULL, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Missing %s address!\n", + cmd->lineno, cmdname); + ret = -EINVAL; + goto err; + } + } + /* Read load destination address. */ + ret = sb_token_to_long(tok, &dest); + if (ret) { + fprintf(stderr, "#%i ERR: Incorrect %s address!\n", + cmd->lineno, cmdname); + goto err; + } + + tok = strtok(NULL, " "); + if (tok) { + ret = sb_token_to_long(tok, &arg); + if (ret) { + fprintf(stderr, + "#%i ERR: Incorrect %s argument!\n", + cmd->lineno, cmdname); + goto err; + } + } + + /* + * Construct the command. + */ + ccmd->header.checksum = 0x5a; + ccmd->header.tag = is_call ? ROM_CALL_CMD : ROM_JUMP_CMD; + ccmd->header.flags = hab; + + ccmd->call.address = dest; + ccmd->call.argument = arg; + + cctx->size = sizeof(*ccmd); + + /* + * Append the command to the last section. + */ + if (!sctx->cmd_head) { + sctx->cmd_head = cctx; + sctx->cmd_tail = cctx; + } else { + sctx->cmd_tail->cmd = cctx; + sctx->cmd_tail = cctx; + } + + return 0; + +err: + free(cctx); + return ret; +} + +static int sb_build_command_jump(struct sb_image_ctx *ictx, + struct sb_cmd_list *cmd) +{ + return sb_build_command_jump_call(ictx, cmd, 0); +} + +static int sb_build_command_call(struct sb_image_ctx *ictx, + struct sb_cmd_list *cmd) +{ + return sb_build_command_jump_call(ictx, cmd, 1); +} + +static int sb_build_command_mode(struct sb_image_ctx *ictx, + struct sb_cmd_list *cmd) +{ + struct sb_section_ctx *sctx = ictx->sect_tail; + struct sb_cmd_ctx *cctx; + struct sb_command *ccmd; + char *tok; + int ret; + unsigned int i; + uint32_t mode = 0xffffffff; + + cctx = calloc(1, sizeof(*cctx)); + if (!cctx) + return -ENOMEM; + + ccmd = &cctx->payload; + + /* + * Prepare the command. + */ + tok = strtok(cmd->cmd, " "); + if (!tok) { + fprintf(stderr, "#%i ERR: Missing MODE boot mode argument!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + + for (i = 0; i < ARRAY_SIZE(modetable); i++) { + if (!strcmp(tok, modetable[i].name)) { + mode = modetable[i].mode; + break; + } + + if (!modetable[i].altname) + continue; + + if (!strcmp(tok, modetable[i].altname)) { + mode = modetable[i].mode; + break; + } + } + + if (mode == 0xffffffff) { + fprintf(stderr, "#%i ERR: Invalid MODE boot mode argument!\n", + cmd->lineno); + ret = -EINVAL; + goto err; + } + + /* + * Construct the command. + */ + ccmd->header.checksum = 0x5a; + ccmd->header.tag = ROM_MODE_CMD; + + ccmd->mode.mode = mode; + + cctx->size = sizeof(*ccmd); + + /* + * Append the command to the last section. + */ + if (!sctx->cmd_head) { + sctx->cmd_head = cctx; + sctx->cmd_tail = cctx; + } else { + sctx->cmd_tail->cmd = cctx; + sctx->cmd_tail = cctx; + } + + return 0; + +err: + free(cctx); + return ret; +} + +static int sb_prefill_image_header(struct sb_image_ctx *ictx) +{ + struct sb_boot_image_header *hdr = &ictx->payload; + + /* Fill signatures */ + memcpy(hdr->signature1, "STMP", 4); + memcpy(hdr->signature2, "sgtl", 4); + + /* SB Image version 1.1 */ + hdr->major_version = SB_VERSION_MAJOR; + hdr->minor_version = SB_VERSION_MINOR; + + /* Boot image major version */ + hdr->product_version.major = htons(0x999); + hdr->product_version.minor = htons(0x999); + hdr->product_version.revision = htons(0x999); + /* Boot image major version */ + hdr->component_version.major = htons(0x999); + hdr->component_version.minor = htons(0x999); + hdr->component_version.revision = htons(0x999); + + /* Drive tag must be 0x0 for i.MX23 */ + hdr->drive_tag = 0; + + hdr->header_blocks = + sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE; + hdr->section_header_size = + sizeof(struct sb_sections_header) / SB_BLOCK_SIZE; + hdr->timestamp_us = sb_get_timestamp() * 1000000; + + /* FIXME -- add proper config option */ + hdr->flags = ictx->verbose_boot ? SB_IMAGE_FLAG_VERBOSE : 0, + + /* FIXME -- We support only default key */ + hdr->key_count = 1; + + return 0; +} + +static int sb_postfill_image_header(struct sb_image_ctx *ictx) +{ + struct sb_boot_image_header *hdr = &ictx->payload; + struct sb_section_ctx *sctx = ictx->sect_head; + uint32_t kd_size, sections_blocks; + EVP_MD_CTX md_ctx; + + /* The main SB header size in blocks. */ + hdr->image_blocks = hdr->header_blocks; + + /* Size of the key dictionary, which has single zero entry. */ + kd_size = hdr->key_count * sizeof(struct sb_key_dictionary_key); + hdr->image_blocks += kd_size / SB_BLOCK_SIZE; + + /* Now count the payloads. */ + hdr->section_count = ictx->sect_count; + while (sctx) { + hdr->image_blocks += sctx->size / SB_BLOCK_SIZE; + sctx = sctx->sect; + } + + if (!ictx->sect_boot_found) { + fprintf(stderr, "ERR: No bootable section selected!\n"); + return -EINVAL; + } + hdr->first_boot_section_id = ictx->sect_boot; + + /* The n * SB section size in blocks. */ + sections_blocks = hdr->section_count * hdr->section_header_size; + hdr->image_blocks += sections_blocks; + + /* Key dictionary offset. */ + hdr->key_dictionary_block = hdr->header_blocks + sections_blocks; + + /* Digest of the whole image. */ + hdr->image_blocks += 2; + + /* Pointer past the dictionary. */ + hdr->first_boot_tag_block = + hdr->key_dictionary_block + kd_size / SB_BLOCK_SIZE; + + /* Compute header digest. */ + EVP_MD_CTX_init(&md_ctx); + + EVP_DigestInit(&md_ctx, EVP_sha1()); + EVP_DigestUpdate(&md_ctx, hdr->signature1, + sizeof(struct sb_boot_image_header) - + sizeof(hdr->digest)); + EVP_DigestFinal(&md_ctx, hdr->digest, NULL); + + return 0; +} + +static int sb_fixup_sections_and_tags(struct sb_image_ctx *ictx) +{ + /* Fixup the placement of sections. */ + struct sb_boot_image_header *ihdr = &ictx->payload; + struct sb_section_ctx *sctx = ictx->sect_head; + struct sb_sections_header *shdr; + struct sb_cmd_ctx *cctx; + struct sb_command *ccmd; + uint32_t offset = ihdr->first_boot_tag_block; + + while (sctx) { + shdr = &sctx->payload; + + /* Fill in the section TAG offset. */ + shdr->section_offset = offset + 1; + offset += shdr->section_size; + + /* Section length is measured from the TAG block. */ + shdr->section_size--; + + /* Fixup the TAG command. */ + cctx = sctx->cmd_head; + while (cctx) { + ccmd = &cctx->payload; + if (ccmd->header.tag == ROM_TAG_CMD) { + ccmd->tag.section_number = shdr->section_number; + ccmd->tag.section_length = shdr->section_size; + ccmd->tag.section_flags = shdr->section_flags; + } + + /* Update the command checksum. */ + ccmd->header.checksum = sb_command_checksum(ccmd); + + cctx = cctx->cmd; + } + + sctx = sctx->sect; + } + + return 0; +} + +static int sb_parse_line(struct sb_image_ctx *ictx, struct sb_cmd_list *cmd) +{ + char *tok; + char *line = cmd->cmd; + char *rptr; + int ret; + + /* Analyze the identifier on this line first. */ + tok = strtok_r(line, " ", &rptr); + if (!tok || (strlen(tok) == 0)) { + fprintf(stderr, "#%i ERR: Invalid line!\n", cmd->lineno); + return -EINVAL; + } + + cmd->cmd = rptr; + + /* DCD */ + if (!strcmp(tok, "DCD")) { + ictx->in_section = 0; + ictx->in_dcd = 1; + sb_build_dcd(ictx, cmd); + return 0; + } + + /* Section */ + if (!strcmp(tok, "SECTION")) { + ictx->in_section = 1; + ictx->in_dcd = 0; + sb_build_section(ictx, cmd); + return 0; + } + + if (!ictx->in_section && !ictx->in_dcd) { + fprintf(stderr, "#%i ERR: Data outside of a section!\n", + cmd->lineno); + return -EINVAL; + } + + if (ictx->in_section) { + /* Section commands */ + if (!strcmp(tok, "NOP")) { + ret = sb_build_command_nop(ictx); + } else if (!strcmp(tok, "TAG")) { + ret = sb_build_command_tag(ictx, cmd); + } else if (!strcmp(tok, "LOAD")) { + ret = sb_build_command_load(ictx, cmd); + } else if (!strcmp(tok, "FILL")) { + ret = sb_build_command_fill(ictx, cmd); + } else if (!strcmp(tok, "JUMP")) { + ret = sb_build_command_jump(ictx, cmd); + } else if (!strcmp(tok, "CALL")) { + ret = sb_build_command_call(ictx, cmd); + } else if (!strcmp(tok, "MODE")) { + ret = sb_build_command_mode(ictx, cmd); + } else { + fprintf(stderr, + "#%i ERR: Unsupported instruction '%s'!\n", + cmd->lineno, tok); + return -ENOTSUP; + } + } else if (ictx->in_dcd) { + char *lptr; + uint32_t ilen = '1'; + + tok = strtok_r(tok, ".", &lptr); + if (!tok || (strlen(tok) == 0) || (lptr && strlen(lptr) != 1)) { + fprintf(stderr, "#%i ERR: Invalid line!\n", + cmd->lineno); + return -EINVAL; + } + + if (lptr && + (lptr[0] != '1' && lptr[0] != '2' && lptr[0] != '4')) { + fprintf(stderr, "#%i ERR: Invalid instruction width!\n", + cmd->lineno); + return -EINVAL; + } + + if (lptr) + ilen = lptr[0] - '1'; + + /* DCD commands */ + if (!strcmp(tok, "WRITE")) { + ret = sb_build_dcd_block(ictx, cmd, + SB_DCD_WRITE | ilen); + } else if (!strcmp(tok, "ANDC")) { + ret = sb_build_dcd_block(ictx, cmd, + SB_DCD_ANDC | ilen); + } else if (!strcmp(tok, "ORR")) { + ret = sb_build_dcd_block(ictx, cmd, + SB_DCD_ORR | ilen); + } else if (!strcmp(tok, "EQZ")) { + ret = sb_build_dcd_block(ictx, cmd, + SB_DCD_CHK_EQZ | ilen); + } else if (!strcmp(tok, "EQ")) { + ret = sb_build_dcd_block(ictx, cmd, + SB_DCD_CHK_EQ | ilen); + } else if (!strcmp(tok, "NEQ")) { + ret = sb_build_dcd_block(ictx, cmd, + SB_DCD_CHK_NEQ | ilen); + } else if (!strcmp(tok, "NEZ")) { + ret = sb_build_dcd_block(ictx, cmd, + SB_DCD_CHK_NEZ | ilen); + } else if (!strcmp(tok, "NOOP")) { + ret = sb_build_dcd_block(ictx, cmd, SB_DCD_NOOP); + } else { + fprintf(stderr, + "#%i ERR: Unsupported instruction '%s'!\n", + cmd->lineno, tok); + return -ENOTSUP; + } + } else { + fprintf(stderr, "#%i ERR: Unsupported instruction '%s'!\n", + cmd->lineno, tok); + return -ENOTSUP; + } + + /* + * Here we have at least one section with one command, otherwise we + * would have failed already higher above. + * + * FIXME -- should the updating happen here ? + */ + if (ictx->in_section && !ret) { + ictx->sect_tail->size += ictx->sect_tail->cmd_tail->size; + ictx->sect_tail->payload.section_size = + ictx->sect_tail->size / SB_BLOCK_SIZE; + } + + return ret; +} + +static int sb_load_cmdfile(struct sb_image_ctx *ictx) +{ + struct sb_cmd_list cmd; + int lineno = 1; + FILE *fp; + char *line = NULL; + ssize_t rlen; + size_t len; + + fp = fopen(ictx->cfg_filename, "r"); + if (!fp) + goto err_file; + + while ((rlen = getline(&line, &len, fp)) > 0) { + memset(&cmd, 0, sizeof(cmd)); + + /* Strip the trailing newline. */ + line[rlen - 1] = '\0'; + + cmd.cmd = line; + cmd.len = rlen; + cmd.lineno = lineno++; + + sb_parse_line(ictx, &cmd); + } + + free(line); + + fclose(fp); + + return 0; + +err_file: + fclose(fp); + fprintf(stderr, "ERR: Failed to load file \"%s\"\n", + ictx->cfg_filename); + return -EINVAL; +} + +static int sb_build_tree_from_cfg(struct sb_image_ctx *ictx) +{ + int ret; + + ret = sb_load_cmdfile(ictx); + if (ret) + return ret; + + ret = sb_prefill_image_header(ictx); + if (ret) + return ret; + + ret = sb_postfill_image_header(ictx); + if (ret) + return ret; + + ret = sb_fixup_sections_and_tags(ictx); + if (ret) + return ret; + + return 0; +} + +static int sb_verify_image_header(struct sb_image_ctx *ictx, + FILE *fp, long fsize) +{ + /* Verify static fields in the image header. */ + struct sb_boot_image_header *hdr = &ictx->payload; + const char *stat[2] = { "[PASS]", "[FAIL]" }; + struct tm tm; + int sz, ret = 0; + unsigned char digest[20]; + EVP_MD_CTX md_ctx; + unsigned long size; + + /* Start image-wide crypto. */ + EVP_MD_CTX_init(&ictx->md_ctx); + EVP_DigestInit(&ictx->md_ctx, EVP_sha1()); + + soprintf(ictx, "---------- Verifying SB Image Header ----------\n"); + + size = fread(&ictx->payload, 1, sizeof(ictx->payload), fp); + if (size != sizeof(ictx->payload)) { + fprintf(stderr, "ERR: SB image header too short!\n"); + return -EINVAL; + } + + /* Compute header digest. */ + EVP_MD_CTX_init(&md_ctx); + EVP_DigestInit(&md_ctx, EVP_sha1()); + EVP_DigestUpdate(&md_ctx, hdr->signature1, + sizeof(struct sb_boot_image_header) - + sizeof(hdr->digest)); + EVP_DigestFinal(&md_ctx, digest, NULL); + + sb_aes_init(ictx, NULL, 1); + sb_encrypt_sb_header(ictx); + + if (memcmp(digest, hdr->digest, 20)) + ret = -EINVAL; + soprintf(ictx, "%s Image header checksum: %s\n", stat[!!ret], + ret ? "BAD" : "OK"); + if (ret) + return ret; + + if (memcmp(hdr->signature1, "STMP", 4) || + memcmp(hdr->signature2, "sgtl", 4)) + ret = -EINVAL; + soprintf(ictx, "%s Signatures: '%.4s' '%.4s'\n", + stat[!!ret], hdr->signature1, hdr->signature2); + if (ret) + return ret; + + if ((hdr->major_version != SB_VERSION_MAJOR) || + ((hdr->minor_version != 1) && (hdr->minor_version != 2))) + ret = -EINVAL; + soprintf(ictx, "%s Image version: v%i.%i\n", stat[!!ret], + hdr->major_version, hdr->minor_version); + if (ret) + return ret; + + ret = sb_get_time(hdr->timestamp_us / 1000000, &tm); + soprintf(ictx, + "%s Creation time: %02i:%02i:%02i %02i/%02i/%04i\n", + stat[!!ret], tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_mday, tm.tm_mon, tm.tm_year + 2000); + if (ret) + return ret; + + soprintf(ictx, "%s Product version: %x.%x.%x\n", stat[0], + ntohs(hdr->product_version.major), + ntohs(hdr->product_version.minor), + ntohs(hdr->product_version.revision)); + soprintf(ictx, "%s Component version: %x.%x.%x\n", stat[0], + ntohs(hdr->component_version.major), + ntohs(hdr->component_version.minor), + ntohs(hdr->component_version.revision)); + + if (hdr->flags & ~SB_IMAGE_FLAG_VERBOSE) + ret = -EINVAL; + soprintf(ictx, "%s Image flags: %s\n", stat[!!ret], + hdr->flags & SB_IMAGE_FLAG_VERBOSE ? "Verbose_boot" : ""); + if (ret) + return ret; + + if (hdr->drive_tag != 0) + ret = -EINVAL; + soprintf(ictx, "%s Drive tag: %i\n", stat[!!ret], + hdr->drive_tag); + if (ret) + return ret; + + sz = sizeof(struct sb_boot_image_header) / SB_BLOCK_SIZE; + if (hdr->header_blocks != sz) + ret = -EINVAL; + soprintf(ictx, "%s Image header size (blocks): %i\n", stat[!!ret], + hdr->header_blocks); + if (ret) + return ret; + + sz = sizeof(struct sb_sections_header) / SB_BLOCK_SIZE; + if (hdr->section_header_size != sz) + ret = -EINVAL; + soprintf(ictx, "%s Section header size (blocks): %i\n", stat[!!ret], + hdr->section_header_size); + if (ret) + return ret; + + soprintf(ictx, "%s Sections count: %i\n", stat[!!ret], + hdr->section_count); + soprintf(ictx, "%s First bootable section %i\n", stat[!!ret], + hdr->first_boot_section_id); + + if (hdr->image_blocks != fsize / SB_BLOCK_SIZE) + ret = -EINVAL; + soprintf(ictx, "%s Image size (blocks): %i\n", stat[!!ret], + hdr->image_blocks); + if (ret) + return ret; + + sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count; + if (hdr->key_dictionary_block != sz) + ret = -EINVAL; + soprintf(ictx, "%s Key dict offset (blocks): %i\n", stat[!!ret], + hdr->key_dictionary_block); + if (ret) + return ret; + + if (hdr->key_count != 1) + ret = -EINVAL; + soprintf(ictx, "%s Number of encryption keys: %i\n", stat[!!ret], + hdr->key_count); + if (ret) + return ret; + + sz = hdr->header_blocks + hdr->section_header_size * hdr->section_count; + sz += hdr->key_count * + sizeof(struct sb_key_dictionary_key) / SB_BLOCK_SIZE; + if (hdr->first_boot_tag_block != (unsigned)sz) + ret = -EINVAL; + soprintf(ictx, "%s First TAG block (blocks): %i\n", stat[!!ret], + hdr->first_boot_tag_block); + if (ret) + return ret; + + return 0; +} + +static void sb_decrypt_tag(struct sb_image_ctx *ictx, + struct sb_cmd_ctx *cctx) +{ + EVP_MD_CTX *md_ctx = &ictx->md_ctx; + struct sb_command *cmd = &cctx->payload; + + sb_aes_crypt(ictx, (uint8_t *)&cctx->c_payload, + (uint8_t *)&cctx->payload, sizeof(*cmd)); + EVP_DigestUpdate(md_ctx, &cctx->c_payload, sizeof(*cmd)); +} + +static int sb_verify_command(struct sb_image_ctx *ictx, + struct sb_cmd_ctx *cctx, FILE *fp, + unsigned long *tsize) +{ + struct sb_command *ccmd = &cctx->payload; + unsigned long size, asize; + char *csum, *flag = ""; + int ret; + unsigned int i; + uint8_t csn, csc = ccmd->header.checksum; + ccmd->header.checksum = 0x5a; + csn = sb_command_checksum(ccmd); + ccmd->header.checksum = csc; + + if (csc == csn) + ret = 0; + else + ret = -EINVAL; + csum = ret ? "checksum BAD" : "checksum OK"; + + switch (ccmd->header.tag) { + case ROM_NOP_CMD: + soprintf(ictx, " NOOP # %s\n", csum); + return ret; + case ROM_TAG_CMD: + if (ccmd->header.flags & ROM_TAG_CMD_FLAG_ROM_LAST_TAG) + flag = "LAST"; + soprintf(ictx, " TAG %s # %s\n", flag, csum); + sb_aes_reinit(ictx, 0); + return ret; + case ROM_LOAD_CMD: + soprintf(ictx, " LOAD addr=0x%08x length=0x%08x # %s\n", + ccmd->load.address, ccmd->load.count, csum); + + cctx->length = ccmd->load.count; + asize = roundup(cctx->length, SB_BLOCK_SIZE); + cctx->data = malloc(asize); + if (!cctx->data) + return -ENOMEM; + + size = fread(cctx->data, 1, asize, fp); + if (size != asize) { + fprintf(stderr, + "ERR: SB LOAD command payload too short!\n"); + return -EINVAL; + } + + *tsize += size; + + EVP_DigestUpdate(&ictx->md_ctx, cctx->data, asize); + sb_aes_crypt(ictx, cctx->data, cctx->data, asize); + + if (ccmd->load.crc32 != crc32(cctx->data, asize)) { + fprintf(stderr, + "ERR: SB LOAD command payload CRC32 invalid!\n"); + return -EINVAL; + } + return 0; + case ROM_FILL_CMD: + soprintf(ictx, + " FILL addr=0x%08x length=0x%08x pattern=0x%08x # %s\n", + ccmd->fill.address, ccmd->fill.count, + ccmd->fill.pattern, csum); + return 0; + case ROM_JUMP_CMD: + if (ccmd->header.flags & ROM_JUMP_CMD_FLAG_HAB) + flag = " HAB"; + soprintf(ictx, + " JUMP%s addr=0x%08x r0_arg=0x%08x # %s\n", + flag, ccmd->fill.address, ccmd->jump.argument, csum); + return 0; + case ROM_CALL_CMD: + if (ccmd->header.flags & ROM_CALL_CMD_FLAG_HAB) + flag = " HAB"; + soprintf(ictx, + " CALL%s addr=0x%08x r0_arg=0x%08x # %s\n", + flag, ccmd->fill.address, ccmd->jump.argument, csum); + return 0; + case ROM_MODE_CMD: + for (i = 0; i < ARRAY_SIZE(modetable); i++) { + if (ccmd->mode.mode == modetable[i].mode) { + soprintf(ictx, " MODE %s # %s\n", + modetable[i].name, csum); + break; + } + } + fprintf(stderr, " MODE !INVALID! # %s\n", csum); + return 0; + } + + return ret; +} + +static int sb_verify_commands(struct sb_image_ctx *ictx, + struct sb_section_ctx *sctx, FILE *fp) +{ + unsigned long size, tsize = 0; + struct sb_cmd_ctx *cctx; + int ret; + + sb_aes_reinit(ictx, 0); + + while (tsize < sctx->size) { + cctx = calloc(1, sizeof(*cctx)); + if (!cctx) + return -ENOMEM; + if (!sctx->cmd_head) { + sctx->cmd_head = cctx; + sctx->cmd_tail = cctx; + } else { + sctx->cmd_tail->cmd = cctx; + sctx->cmd_tail = cctx; + } + + size = fread(&cctx->c_payload, 1, sizeof(cctx->c_payload), fp); + if (size != sizeof(cctx->c_payload)) { + fprintf(stderr, "ERR: SB command header too short!\n"); + return -EINVAL; + } + + tsize += size; + + sb_decrypt_tag(ictx, cctx); + + ret = sb_verify_command(ictx, cctx, fp, &tsize); + if (ret) + return -EINVAL; + } + + return 0; +} + +static int sb_verify_sections_cmds(struct sb_image_ctx *ictx, FILE *fp) +{ + struct sb_boot_image_header *hdr = &ictx->payload; + struct sb_sections_header *shdr; + unsigned int i; + int ret; + struct sb_section_ctx *sctx; + unsigned long size; + char *bootable = ""; + + soprintf(ictx, "----- Verifying SB Sections and Commands -----\n"); + + for (i = 0; i < hdr->section_count; i++) { + sctx = calloc(1, sizeof(*sctx)); + if (!sctx) + return -ENOMEM; + if (!ictx->sect_head) { + ictx->sect_head = sctx; + ictx->sect_tail = sctx; + } else { + ictx->sect_tail->sect = sctx; + ictx->sect_tail = sctx; + } + + size = fread(&sctx->payload, 1, sizeof(sctx->payload), fp); + if (size != sizeof(sctx->payload)) { + fprintf(stderr, "ERR: SB section header too short!\n"); + return -EINVAL; + } + } + + size = fread(&ictx->sb_dict_key, 1, sizeof(ictx->sb_dict_key), fp); + if (size != sizeof(ictx->sb_dict_key)) { + fprintf(stderr, "ERR: SB key dictionary too short!\n"); + return -EINVAL; + } + + sb_encrypt_sb_sections_header(ictx); + sb_aes_reinit(ictx, 0); + sb_decrypt_key_dictionary_key(ictx); + + sb_aes_reinit(ictx, 0); + + sctx = ictx->sect_head; + while (sctx) { + shdr = &sctx->payload; + + if (shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) { + sctx->boot = 1; + bootable = " BOOTABLE"; + } + + sctx->size = (shdr->section_size * SB_BLOCK_SIZE) + + sizeof(struct sb_command); + soprintf(ictx, "SECTION 0x%x%s # size = %i bytes\n", + shdr->section_number, bootable, sctx->size); + + if (shdr->section_flags & ~SB_SECTION_FLAG_BOOTABLE) + fprintf(stderr, " WARN: Unknown section flag(s) %08x\n", + shdr->section_flags); + + if ((shdr->section_flags & SB_SECTION_FLAG_BOOTABLE) && + (hdr->first_boot_section_id != shdr->section_number)) { + fprintf(stderr, + " WARN: Bootable section does ID not match image header ID!\n"); + } + + ret = sb_verify_commands(ictx, sctx, fp); + if (ret) + return ret; + + sctx = sctx->sect; + } + + /* + * FIXME IDEA: + * check if the first TAG command is at sctx->section_offset + */ + return 0; +} + +static int sb_verify_image_end(struct sb_image_ctx *ictx, + FILE *fp, off_t filesz) +{ + uint8_t digest[32]; + unsigned long size; + off_t pos; + int ret; + + soprintf(ictx, "------------- Verifying image end -------------\n"); + + size = fread(digest, 1, sizeof(digest), fp); + if (size != sizeof(digest)) { + fprintf(stderr, "ERR: SB key dictionary too short!\n"); + return -EINVAL; + } + + pos = ftell(fp); + if (pos != filesz) { + fprintf(stderr, "ERR: Trailing data past the image!\n"); + return -EINVAL; + } + + /* Check the image digest. */ + EVP_DigestFinal(&ictx->md_ctx, ictx->digest, NULL); + + /* Decrypt the image digest from the input image. */ + sb_aes_reinit(ictx, 0); + sb_aes_crypt(ictx, digest, digest, sizeof(digest)); + + /* Check all of 20 bytes of the SHA1 hash. */ + ret = memcmp(digest, ictx->digest, 20) ? -EINVAL : 0; + + if (ret) + soprintf(ictx, "[FAIL] Full-image checksum: BAD\n"); + else + soprintf(ictx, "[PASS] Full-image checksum: OK\n"); + + return ret; +} + + +static int sb_build_tree_from_img(struct sb_image_ctx *ictx) +{ + long filesize; + int ret; + FILE *fp; + + if (!ictx->input_filename) { + fprintf(stderr, "ERR: Missing filename!\n"); + return -EINVAL; + } + + fp = fopen(ictx->input_filename, "r"); + if (!fp) + goto err_open; + + ret = fseek(fp, 0, SEEK_END); + if (ret < 0) + goto err_file; + + filesize = ftell(fp); + if (filesize < 0) + goto err_file; + + ret = fseek(fp, 0, SEEK_SET); + if (ret < 0) + goto err_file; + + if (filesize < (signed)sizeof(ictx->payload)) { + fprintf(stderr, "ERR: File too short!\n"); + goto err_file; + } + + if (filesize & (SB_BLOCK_SIZE - 1)) { + fprintf(stderr, "ERR: The file is not aligned!\n"); + goto err_file; + } + + /* Load and verify image header */ + ret = sb_verify_image_header(ictx, fp, filesize); + if (ret) + goto err_verify; + + /* Load and verify sections and commands */ + ret = sb_verify_sections_cmds(ictx, fp); + if (ret) + goto err_verify; + + ret = sb_verify_image_end(ictx, fp, filesize); + if (ret) + goto err_verify; + + ret = 0; + +err_verify: + soprintf(ictx, "-------------------- Result -------------------\n"); + soprintf(ictx, "Verification %s\n", ret ? "FAILED" : "PASSED"); + + /* Stop the encryption session. */ + sb_aes_deinit(&ictx->cipher_ctx); + + fclose(fp); + return ret; + +err_file: + fclose(fp); +err_open: + fprintf(stderr, "ERR: Failed to load file \"%s\"\n", + ictx->input_filename); + return -EINVAL; +} + +static void sb_free_image(struct sb_image_ctx *ictx) +{ + struct sb_section_ctx *sctx = ictx->sect_head, *s_head; + struct sb_dcd_ctx *dctx = ictx->dcd_head, *d_head; + struct sb_cmd_ctx *cctx, *c_head; + + while (sctx) { + s_head = sctx; + c_head = sctx->cmd_head; + + while (c_head) { + cctx = c_head; + c_head = c_head->cmd; + if (cctx->data) + free(cctx->data); + free(cctx); + } + + sctx = sctx->sect; + free(s_head); + } + + while (dctx) { + d_head = dctx; + dctx = dctx->dcd; + free(d_head->payload); + free(d_head); + } +} + +/* + * MXSSB-MKIMAGE glue code. + */ +static int mxsimage_check_image_types(uint8_t type) +{ + if (type == IH_TYPE_MXSIMAGE) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +} + +static void mxsimage_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ +} + +int mxsimage_check_params(struct image_tool_params *params) +{ + if (!params) + return -1; + if (!strlen(params->imagename)) { + fprintf(stderr, + "Error: %s - Configuration file not specified, it is needed for mxsimage generation\n", + params->cmdname); + return -1; + } + + /* + * Check parameters: + * XIP is not allowed and verify that incompatible + * parameters are not sent at the same time + * For example, if list is required a data image must not be provided + */ + return (params->dflag && (params->fflag || params->lflag)) || + (params->fflag && (params->dflag || params->lflag)) || + (params->lflag && (params->dflag || params->fflag)) || + (params->xflag) || !(strlen(params->imagename)); +} + +static int mxsimage_verify_print_header(char *file, int silent) +{ + int ret; + struct sb_image_ctx ctx; + + memset(&ctx, 0, sizeof(ctx)); + + ctx.input_filename = file; + ctx.silent_dump = silent; + + ret = sb_build_tree_from_img(&ctx); + sb_free_image(&ctx); + + return ret; +} + +char *imagefile; +static int mxsimage_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + struct sb_boot_image_header *hdr; + + if (!ptr) + return -EINVAL; + + hdr = (struct sb_boot_image_header *)ptr; + + /* + * Check if the header contains the MXS image signatures, + * if so, do a full-image verification. + */ + if (memcmp(hdr->signature1, "STMP", 4) || + memcmp(hdr->signature2, "sgtl", 4)) + return -EINVAL; + + imagefile = params->imagefile; + + return mxsimage_verify_print_header(params->imagefile, 1); +} + +static void mxsimage_print_header(const void *hdr) +{ + if (imagefile) + mxsimage_verify_print_header(imagefile, 0); +} + +static int sb_build_image(struct sb_image_ctx *ictx, + struct image_type_params *tparams) +{ + struct sb_boot_image_header *sb_header = &ictx->payload; + struct sb_section_ctx *sctx; + struct sb_cmd_ctx *cctx; + struct sb_command *ccmd; + struct sb_key_dictionary_key *sb_dict_key = &ictx->sb_dict_key; + + uint8_t *image, *iptr; + + /* Calculate image size. */ + uint32_t size = sizeof(*sb_header) + + ictx->sect_count * sizeof(struct sb_sections_header) + + sizeof(*sb_dict_key) + sizeof(ictx->digest); + + sctx = ictx->sect_head; + while (sctx) { + size += sctx->size; + sctx = sctx->sect; + }; + + image = malloc(size); + if (!image) + return -ENOMEM; + iptr = image; + + memcpy(iptr, sb_header, sizeof(*sb_header)); + iptr += sizeof(*sb_header); + + sctx = ictx->sect_head; + while (sctx) { + memcpy(iptr, &sctx->payload, sizeof(struct sb_sections_header)); + iptr += sizeof(struct sb_sections_header); + sctx = sctx->sect; + }; + + memcpy(iptr, sb_dict_key, sizeof(*sb_dict_key)); + iptr += sizeof(*sb_dict_key); + + sctx = ictx->sect_head; + while (sctx) { + cctx = sctx->cmd_head; + while (cctx) { + ccmd = &cctx->payload; + + memcpy(iptr, &cctx->c_payload, sizeof(cctx->payload)); + iptr += sizeof(cctx->payload); + + if (ccmd->header.tag == ROM_LOAD_CMD) { + memcpy(iptr, cctx->data, cctx->length); + iptr += cctx->length; + } + + cctx = cctx->cmd; + } + + sctx = sctx->sect; + }; + + memcpy(iptr, ictx->digest, sizeof(ictx->digest)); + iptr += sizeof(ictx->digest); + + /* Configure the mkimage */ + tparams->hdr = image; + tparams->header_size = size; + + return 0; +} + +static int mxsimage_generate(struct image_tool_params *params, + struct image_type_params *tparams) +{ + int ret; + struct sb_image_ctx ctx; + + /* Do not copy the U-Boot image! */ + params->skipcpy = 1; + + memset(&ctx, 0, sizeof(ctx)); + + ctx.cfg_filename = params->imagename; + ctx.output_filename = params->imagefile; + ctx.verbose_boot = 1; + + ret = sb_build_tree_from_cfg(&ctx); + if (ret) + goto fail; + + ret = sb_encrypt_image(&ctx); + if (!ret) + ret = sb_build_image(&ctx, tparams); + +fail: + sb_free_image(&ctx); + + return ret; +} + +/* + * mxsimage parameters + */ +static struct image_type_params mxsimage_params = { + .name = "Freescale MXS Boot Image support", + .header_size = 0, + .hdr = NULL, + .check_image_type = mxsimage_check_image_types, + .verify_header = mxsimage_verify_header, + .print_header = mxsimage_print_header, + .set_header = mxsimage_set_header, + .check_params = mxsimage_check_params, + .vrec_header = mxsimage_generate, +}; + +void init_mxs_image_type(void) +{ + register_image_type(&mxsimage_params); +} + +#else +void init_mxs_image_type(void) +{ +} +#endif diff --git a/qemu/roms/u-boot/tools/mxsimage.h b/qemu/roms/u-boot/tools/mxsimage.h new file mode 100644 index 000000000..6cd59d2db --- /dev/null +++ b/qemu/roms/u-boot/tools/mxsimage.h @@ -0,0 +1,230 @@ +/* + * Freescale i.MX28 SB image generator + * + * Copyright (C) 2012 Marek Vasut <marex@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __MXSSB_H__ +#define __MXSSB_H__ + +#include <stdint.h> +#include <arpa/inet.h> + +#define SB_BLOCK_SIZE 16 + +#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +struct sb_boot_image_version { + uint16_t major; + uint16_t pad0; + uint16_t minor; + uint16_t pad1; + uint16_t revision; + uint16_t pad2; +}; + +struct sb_boot_image_header { + union { + /* SHA1 of the header. */ + uint8_t digest[20]; + struct { + /* CBC-MAC initialization vector. */ + uint8_t iv[16]; + uint8_t extra[4]; + }; + }; + /* 'STMP' */ + uint8_t signature1[4]; + /* Major version of the image format. */ + uint8_t major_version; + /* Minor version of the image format. */ + uint8_t minor_version; + /* Flags associated with the image. */ + uint16_t flags; + /* Size of the image in 16b blocks. */ + uint32_t image_blocks; + /* Offset of the first tag in 16b blocks. */ + uint32_t first_boot_tag_block; + /* ID of the section to boot from. */ + uint32_t first_boot_section_id; + /* Amount of crypto keys. */ + uint16_t key_count; + /* Offset to the key dictionary in 16b blocks. */ + uint16_t key_dictionary_block; + /* Size of this header in 16b blocks. */ + uint16_t header_blocks; + /* Amount of section headers. */ + uint16_t section_count; + /* Section header size in 16b blocks. */ + uint16_t section_header_size; + /* Padding to align timestamp to uint64_t. */ + uint8_t padding0[2]; + /* 'sgtl' (since v1.1) */ + uint8_t signature2[4]; + /* Image generation date, in microseconds since 1.1.2000 . */ + uint64_t timestamp_us; + /* Product version. */ + struct sb_boot_image_version + product_version; + /* Component version. */ + struct sb_boot_image_version + component_version; + /* Drive tag for the system drive. (since v1.1) */ + uint16_t drive_tag; + /* Padding. */ + uint8_t padding1[6]; +}; + +#define SB_VERSION_MAJOR 1 +#define SB_VERSION_MINOR 1 + +/* Enable to HTLLC verbose boot report. */ +#define SB_IMAGE_FLAG_VERBOSE (1 << 0) + +struct sb_key_dictionary_key { + /* The CBC-MAC of image and sections header. */ + uint8_t cbc_mac[SB_BLOCK_SIZE]; + /* The AES key encrypted by image key (zero). */ + uint8_t key[SB_BLOCK_SIZE]; +}; + +struct sb_ivt_header { + uint32_t header; + uint32_t entry; + uint32_t reserved1; + uint32_t dcd; + uint32_t boot_data; + uint32_t self; + uint32_t csf; + uint32_t reserved2; +}; + +#define SB_HAB_IVT_TAG 0xd1UL +#define SB_HAB_DCD_TAG 0xd2UL + +#define SB_HAB_VERSION 0x40UL + +/* + * The "size" field in the IVT header is not naturally aligned, + * use this macro to fill first 4 bytes of the IVT header without + * causing issues on some systems (esp. M68k, PPC, MIPS-BE, ARM-BE). + */ +static inline uint32_t sb_hab_ivt_header(void) +{ + uint32_t ret = 0; + ret |= SB_HAB_IVT_TAG << 24; + ret |= sizeof(struct sb_ivt_header) << 16; + ret |= SB_HAB_VERSION; + return htonl(ret); +} + +struct sb_sections_header { + /* Section number. */ + uint32_t section_number; + /* Offset of this sections first instruction after "TAG". */ + uint32_t section_offset; + /* Size of the section in 16b blocks. */ + uint32_t section_size; + /* Section flags. */ + uint32_t section_flags; +}; + +#define SB_SECTION_FLAG_BOOTABLE (1 << 0) + +struct sb_command { + struct { + uint8_t checksum; + uint8_t tag; + uint16_t flags; +#define ROM_TAG_CMD_FLAG_ROM_LAST_TAG 0x1 +#define ROM_LOAD_CMD_FLAG_DCD_LOAD 0x1 /* MX28 only */ +#define ROM_JUMP_CMD_FLAG_HAB 0x1 /* MX28 only */ +#define ROM_CALL_CMD_FLAG_HAB 0x1 /* MX28 only */ + } header; + + union { + struct { + uint32_t reserved[3]; + } nop; + struct { + uint32_t section_number; + uint32_t section_length; + uint32_t section_flags; + } tag; + struct { + uint32_t address; + uint32_t count; + uint32_t crc32; + } load; + struct { + uint32_t address; + uint32_t count; + uint32_t pattern; + } fill; + struct { + uint32_t address; + uint32_t reserved; + /* Passed in register r0 before JUMP */ + uint32_t argument; + } jump; + struct { + uint32_t address; + uint32_t reserved; + /* Passed in register r0 before CALL */ + uint32_t argument; + } call; + struct { + uint32_t reserved1; + uint32_t reserved2; + uint32_t mode; + } mode; + + }; +}; + +/* + * Most of the mode names are same or at least similar + * on i.MX23 and i.MX28, but some of the mode names + * differ. The "name" field represents the mode name + * on i.MX28 as seen in Table 12-2 of the datasheet. + * The "altname" field represents the differently named + * fields on i.MX23 as seen in Table 35-3 of the + * datasheet. + */ +static const struct { + const char *name; + const char *altname; + const uint8_t mode; +} modetable[] = { + { "USB", NULL, 0x00 }, + { "I2C", NULL, 0x01 }, + { "SPI2_FLASH", "SPI1_FLASH", 0x02 }, + { "SPI3_FLASH", "SPI2_FLASH", 0x03 }, + { "NAND_BCH", NULL, 0x04 }, + { "JTAG", NULL, 0x06 }, + { "SPI3_EEPROM", "SPI2_EEPROM", 0x08 }, + { "SD_SSP0", NULL, 0x09 }, + { "SD_SSP1", NULL, 0x0A } +}; + +enum sb_tag { + ROM_NOP_CMD = 0x00, + ROM_TAG_CMD = 0x01, + ROM_LOAD_CMD = 0x02, + ROM_FILL_CMD = 0x03, + ROM_JUMP_CMD = 0x04, + ROM_CALL_CMD = 0x05, + ROM_MODE_CMD = 0x06 +}; + +struct sb_source_entry { + uint8_t tag; + uint32_t address; + uint32_t flags; + char *filename; +}; + +#endif /* __MXSSB_H__ */ diff --git a/qemu/roms/u-boot/tools/ncb.c b/qemu/roms/u-boot/tools/ncb.c new file mode 100644 index 000000000..ec8d8a743 --- /dev/null +++ b/qemu/roms/u-boot/tools/ncb.c @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> + +int main (int argc, char *argv[]) +{ + int s, len, o, port = 6666; + char buf[512]; + struct sockaddr_in addr; + socklen_t addr_len = sizeof addr; + + if (argc > 1) + port = atoi (argv[1]); + + s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); + + o = 1; + len = 4; + setsockopt (3, SOL_SOCKET, SO_REUSEADDR, &o, len); + + addr.sin_family = AF_INET; + addr.sin_port = htons (port); + addr.sin_addr.s_addr = INADDR_ANY; /* receive broadcasts */ + + bind (s, (struct sockaddr *) &addr, sizeof addr); + + for (;;) { + len = recvfrom (s, buf, sizeof buf, 0, (struct sockaddr *) &addr, &addr_len); + if (len < 0) + break; + if (write (1, buf, len) != len) + fprintf(stderr, "WARNING: serial characters dropped\n"); + } + + return 0; +} diff --git a/qemu/roms/u-boot/tools/netconsole b/qemu/roms/u-boot/tools/netconsole new file mode 100755 index 000000000..1a0ef2224 --- /dev/null +++ b/qemu/roms/u-boot/tools/netconsole @@ -0,0 +1,63 @@ +#!/bin/sh + +usage() { + ( + echo "Usage: $0 <board-IP> [board-port [board-in-port]]" + echo "" + echo "If port is not specified, '6666' will be used" + [ -z "$*" ] && exit 0 + echo "" + echo "ERROR: $*" + exit 1 + ) 1>&2 + exit $? +} + +while [ -n "$1" ] ; do + case $1 in + -h|--help) usage;; + --) break;; + -*) usage "Invalid option $1";; + *) break;; + esac + shift +done + +ip=$1 +board_out_port=${2:-6666} +board_in_port=${3:-${board_out_port}} + +echo Board out port: ${board_out_port} +echo Board in port: ${board_in_port} + +if [ -z "${ip}" ] || [ -n "$4" ] ; then + usage "Invalid number of arguments" +fi + +for nc in netcat nc ; do + type ${nc} >/dev/null 2>&1 && break +done + +trap "stty icanon echo intr ^C" 0 2 3 5 10 13 15 +echo "NOTE: the interrupt signal (normally ^C) has been remapped to ^T" + +stty -icanon -echo intr ^T +( +if type ncb 2>/dev/null ; then + # see if ncb is in $PATH + exec ncb ${board_out_port} + +elif [ -x ${0%/*}/ncb ] ; then + # maybe it's in the same dir as the netconsole script + exec ${0%/*}/ncb ${board_out_port} + +else + # blah, just use regular netcat + while ${nc} -u -l -p ${board_out_port} < /dev/null ; do + : + done +fi +) & +pid=$! +${nc} -u ${ip} ${board_in_port} +kill ${pid} 2>/dev/null diff --git a/qemu/roms/u-boot/tools/omap/clocks_get_m_n.c b/qemu/roms/u-boot/tools/omap/clocks_get_m_n.c new file mode 100644 index 000000000..57e25753a --- /dev/null +++ b/qemu/roms/u-boot/tools/omap/clocks_get_m_n.c @@ -0,0 +1,186 @@ +/* + * Program for finding M & N values for DPLLs + * To be run on Host PC + * + * (C) Copyright 2010 + * Texas Instruments, <www.ti.com> + * + * Aneesh V <aneesh@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <stdlib.h> +#include <stdio.h> +typedef unsigned int u32; +#define MAX_N 127 + +/* + * get_m_n_optimized() - Finds optimal DPLL multiplier(M) and divider(N) + * values based on the reference frequency, required output frequency, + * maximum tolerance for output frequency etc. + * + * target_freq_khz - output frequency required in KHz + * ref_freq_khz - reference(input) frequency in KHz + * m - pointer to computed M value + * n - pointer to computed N value + * tolerance_khz - tolerance for the output frequency. When the algorithm + * succeeds in finding vialble M and N values the corresponding output + * frequency will be in the range: + * [target_freq_khz - tolerance_khz, target_freq_khz] + * + * Formula: + * Fdpll = (2 * M * Fref) / (N + 1) + * + * Considerations for lock-time: + * - Smaller the N, better lock-time, especially lock-time will be + * - For acceptable lock-times: + * Fref / (M + 1) >= 1 MHz + * + * Considerations for power: + * - The difference in power for different N values giving the same + * output is negligible. So, we optimize for lock-time + * + * Hard-constraints: + * - N can not be greater than 127(7 bit field for representing N) + * + * Usage: + * $ gcc clocks_get_m_n.c + * $ ./a.out + */ +int get_m_n_optimized(u32 target_freq_khz, u32 ref_freq_khz, u32 *M, u32 *N) +{ + u32 freq = target_freq_khz; + u32 m_optimal, n_optimal, freq_optimal = 0, freq_old; + u32 m, n; + n = 1; + while (1) { + m = target_freq_khz / ref_freq_khz / 2 * n; + freq_old = 0; + while (1) { + freq = ref_freq_khz * 2 * m / n; + if (freq > target_freq_khz) { + freq = freq_old; + m--; + break; + } + m++; + freq_old = freq; + } + if (freq > freq_optimal) { + freq_optimal = freq; + m_optimal = m; + n_optimal = n; + } + n++; + if ((freq_optimal == target_freq_khz) || + ((ref_freq_khz / n) < 1000)) { + break; + } + } + n--; + *M = m_optimal; + *N = n_optimal - 1; + printf("ref %d m %d n %d target %d locked %d\n", ref_freq_khz, + m_optimal, n_optimal - 1, target_freq_khz, freq_optimal); + return 0; +} + +void main(void) +{ + u32 m, n; + printf("\nMPU - 2000000\n"); + get_m_n_optimized(2000000, 12000, &m, &n); + get_m_n_optimized(2000000, 13000, &m, &n); + get_m_n_optimized(2000000, 16800, &m, &n); + get_m_n_optimized(2000000, 19200, &m, &n); + get_m_n_optimized(2000000, 26000, &m, &n); + get_m_n_optimized(2000000, 27000, &m, &n); + get_m_n_optimized(2000000, 38400, &m, &n); + + printf("\nMPU - 1200000\n"); + get_m_n_optimized(1200000, 12000, &m, &n); + get_m_n_optimized(1200000, 13000, &m, &n); + get_m_n_optimized(1200000, 16800, &m, &n); + get_m_n_optimized(1200000, 19200, &m, &n); + get_m_n_optimized(1200000, 26000, &m, &n); + get_m_n_optimized(1200000, 27000, &m, &n); + get_m_n_optimized(1200000, 38400, &m, &n); + + printf("\nMPU - 1584000\n"); + get_m_n_optimized(1584000, 12000, &m, &n); + get_m_n_optimized(1584000, 13000, &m, &n); + get_m_n_optimized(1584000, 16800, &m, &n); + get_m_n_optimized(1584000, 19200, &m, &n); + get_m_n_optimized(1584000, 26000, &m, &n); + get_m_n_optimized(1584000, 27000, &m, &n); + get_m_n_optimized(1584000, 38400, &m, &n); + + printf("\nCore 1600000\n"); + get_m_n_optimized(1600000, 12000, &m, &n); + get_m_n_optimized(1600000, 13000, &m, &n); + get_m_n_optimized(1600000, 16800, &m, &n); + get_m_n_optimized(1600000, 19200, &m, &n); + get_m_n_optimized(1600000, 26000, &m, &n); + get_m_n_optimized(1600000, 27000, &m, &n); + get_m_n_optimized(1600000, 38400, &m, &n); + + printf("\nPER 1536000\n"); + get_m_n_optimized(1536000, 12000, &m, &n); + get_m_n_optimized(1536000, 13000, &m, &n); + get_m_n_optimized(1536000, 16800, &m, &n); + get_m_n_optimized(1536000, 19200, &m, &n); + get_m_n_optimized(1536000, 26000, &m, &n); + get_m_n_optimized(1536000, 27000, &m, &n); + get_m_n_optimized(1536000, 38400, &m, &n); + + printf("\nIVA 1862000\n"); + get_m_n_optimized(1862000, 12000, &m, &n); + get_m_n_optimized(1862000, 13000, &m, &n); + get_m_n_optimized(1862000, 16800, &m, &n); + get_m_n_optimized(1862000, 19200, &m, &n); + get_m_n_optimized(1862000, 26000, &m, &n); + get_m_n_optimized(1862000, 27000, &m, &n); + get_m_n_optimized(1862000, 38400, &m, &n); + + printf("\nIVA Nitro - 1290000\n"); + get_m_n_optimized(1290000, 12000, &m, &n); + get_m_n_optimized(1290000, 13000, &m, &n); + get_m_n_optimized(1290000, 16800, &m, &n); + get_m_n_optimized(1290000, 19200, &m, &n); + get_m_n_optimized(1290000, 26000, &m, &n); + get_m_n_optimized(1290000, 27000, &m, &n); + get_m_n_optimized(1290000, 38400, &m, &n); + + printf("\nABE 196608 sys clk\n"); + get_m_n_optimized(196608, 12000, &m, &n); + get_m_n_optimized(196608, 13000, &m, &n); + get_m_n_optimized(196608, 16800, &m, &n); + get_m_n_optimized(196608, 19200, &m, &n); + get_m_n_optimized(196608, 26000, &m, &n); + get_m_n_optimized(196608, 27000, &m, &n); + get_m_n_optimized(196608, 38400, &m, &n); + + printf("\nABE 196608 32K\n"); + get_m_n_optimized(196608000/4, 32768, &m, &n); + + printf("\nUSB 1920000\n"); + get_m_n_optimized(1920000, 12000, &m, &n); + get_m_n_optimized(1920000, 13000, &m, &n); + get_m_n_optimized(1920000, 16800, &m, &n); + get_m_n_optimized(1920000, 19200, &m, &n); + get_m_n_optimized(1920000, 26000, &m, &n); + get_m_n_optimized(1920000, 27000, &m, &n); + get_m_n_optimized(1920000, 38400, &m, &n); + + printf("\nCore ES1 1523712\n"); + get_m_n_optimized(1524000, 12000, &m, &n); + get_m_n_optimized(1524000, 13000, &m, &n); + get_m_n_optimized(1524000, 16800, &m, &n); + get_m_n_optimized(1524000, 19200, &m, &n); + get_m_n_optimized(1524000, 26000, &m, &n); + get_m_n_optimized(1524000, 27000, &m, &n); + + /* exact recommendation for SDPs */ + get_m_n_optimized(1523712, 38400, &m, &n); + +} diff --git a/qemu/roms/u-boot/tools/omapimage.c b/qemu/roms/u-boot/tools/omapimage.c new file mode 100644 index 000000000..1e0c16479 --- /dev/null +++ b/qemu/roms/u-boot/tools/omapimage.c @@ -0,0 +1,179 @@ +/* + * (C) Copyright 2010 + * Linaro LTD, www.linaro.org + * Author: John Rigby <john.rigby@linaro.org> + * Based on TI's signGP.c + * + * (C) Copyright 2009 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * (C) Copyright 2008 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include <compiler.h> +#include <image.h> +#include "gpheader.h" +#include "omapimage.h" + +/* Header size is CH header rounded up to 512 bytes plus GP header */ +#define OMAP_CH_HDR_SIZE 512 +#define OMAP_FILE_HDR_SIZE (OMAP_CH_HDR_SIZE + GPIMAGE_HDR_SIZE) + +static int do_swap32 = 0; + +static uint8_t omapimage_header[OMAP_FILE_HDR_SIZE]; + +static int omapimage_check_image_types(uint8_t type) +{ + if (type == IH_TYPE_OMAPIMAGE) + return EXIT_SUCCESS; + return EXIT_FAILURE; +} + +static int omapimage_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + struct ch_toc *toc = (struct ch_toc *)ptr; + struct gp_header *gph = (struct gp_header *)(ptr+OMAP_CH_HDR_SIZE); + uint32_t offset, size; + + while (toc->section_offset != 0xffffffff + && toc->section_size != 0xffffffff) { + if (do_swap32) { + offset = cpu_to_be32(toc->section_offset); + size = cpu_to_be32(toc->section_size); + } else { + offset = toc->section_offset; + size = toc->section_size; + } + if (!offset || !size) + return -1; + if (offset >= OMAP_CH_HDR_SIZE || + offset+size >= OMAP_CH_HDR_SIZE) + return -1; + toc++; + } + + return gph_verify_header(gph, do_swap32); +} + +static void omapimage_print_section(struct ch_settings *chs) +{ + const char *section_name; + + if (chs->section_key) + section_name = "CHSETTINGS"; + else + section_name = "UNKNOWNKEY"; + + printf("%s (%x) " + "valid:%x " + "version:%x " + "reserved:%x " + "flags:%x\n", + section_name, + chs->section_key, + chs->valid, + chs->version, + chs->reserved, + chs->flags); +} + +static void omapimage_print_header(const void *ptr) +{ + const struct ch_toc *toc = (struct ch_toc *)ptr; + const struct gp_header *gph = + (struct gp_header *)(ptr+OMAP_CH_HDR_SIZE); + uint32_t offset, size; + + while (toc->section_offset != 0xffffffff + && toc->section_size != 0xffffffff) { + if (do_swap32) { + offset = cpu_to_be32(toc->section_offset); + size = cpu_to_be32(toc->section_size); + } else { + offset = toc->section_offset; + size = toc->section_size; + } + + if (offset >= OMAP_CH_HDR_SIZE || + offset+size >= OMAP_CH_HDR_SIZE) + exit(EXIT_FAILURE); + + printf("Section %s offset %x length %x\n", + toc->section_name, + toc->section_offset, + toc->section_size); + + omapimage_print_section((struct ch_settings *)(ptr+offset)); + toc++; + } + + gph_print_header(gph, do_swap32); +} + +static int toc_offset(void *hdr, void *member) +{ + return member - hdr; +} + +static void omapimage_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + struct ch_toc *toc = (struct ch_toc *)ptr; + struct ch_settings *chs = (struct ch_settings *) + (ptr + 2 * sizeof(*toc)); + struct gp_header *gph = (struct gp_header *)(ptr + OMAP_CH_HDR_SIZE); + + toc->section_offset = toc_offset(ptr, chs); + toc->section_size = sizeof(struct ch_settings); + strcpy((char *)toc->section_name, "CHSETTINGS"); + + chs->section_key = KEY_CHSETTINGS; + chs->valid = 0; + chs->version = 1; + chs->reserved = 0; + chs->flags = 0; + + toc++; + memset(toc, 0xff, sizeof(*toc)); + + gph_set_header(gph, sbuf->st_size - OMAP_FILE_HDR_SIZE, + params->addr, 0); + + if (strncmp(params->imagename, "byteswap", 8) == 0) { + do_swap32 = 1; + int swapped = 0; + uint32_t *data = (uint32_t *)ptr; + + while (swapped <= (sbuf->st_size / sizeof(uint32_t))) { + *data = cpu_to_be32(*data); + swapped++; + data++; + } + } +} + +/* + * omapimage parameters + */ +static struct image_type_params omapimage_params = { + .name = "TI OMAP CH/GP Boot Image support", + .header_size = OMAP_FILE_HDR_SIZE, + .hdr = (void *)&omapimage_header, + .check_image_type = omapimage_check_image_types, + .verify_header = omapimage_verify_header, + .print_header = omapimage_print_header, + .set_header = omapimage_set_header, + .check_params = gpimage_check_params, +}; + +void init_omap_image_type(void) +{ + register_image_type(&omapimage_params); +} diff --git a/qemu/roms/u-boot/tools/omapimage.h b/qemu/roms/u-boot/tools/omapimage.h new file mode 100644 index 000000000..8744ae7a2 --- /dev/null +++ b/qemu/roms/u-boot/tools/omapimage.h @@ -0,0 +1,29 @@ +/* + * (C) Copyright 2010 + * Linaro LTD, www.linaro.org + * Author John Rigby <john.rigby@linaro.org> + * Based on TI's signGP.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _OMAPIMAGE_H_ +#define _OMAPIMAGE_H_ + +struct ch_toc { + uint32_t section_offset; + uint32_t section_size; + uint8_t unused[12]; + uint8_t section_name[12]; +}; + +struct ch_settings { + uint32_t section_key; + uint8_t valid; + uint8_t version; + uint16_t reserved; + uint32_t flags; +}; + +#define KEY_CHSETTINGS 0xC0C0C0C1 +#endif /* _OMAPIMAGE_H_ */ diff --git a/qemu/roms/u-boot/tools/os_support.c b/qemu/roms/u-boot/tools/os_support.c new file mode 100644 index 000000000..f7651d0e1 --- /dev/null +++ b/qemu/roms/u-boot/tools/os_support.c @@ -0,0 +1,16 @@ +/* + * Copyright 2009 Extreme Engineering Solutions, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + */ + +/* + * Include additional files required for supporting different operating systems + */ +#include "compiler.h" +#ifdef __MINGW32__ +#include "mingw_support.c" +#endif +#if defined(__APPLE__) && __DARWIN_C_LEVEL < 200809L +#include "getline.c" +#endif diff --git a/qemu/roms/u-boot/tools/os_support.h b/qemu/roms/u-boot/tools/os_support.h new file mode 100644 index 000000000..695ffcfe7 --- /dev/null +++ b/qemu/roms/u-boot/tools/os_support.h @@ -0,0 +1,23 @@ +/* + * Copyright 2009 Extreme Engineering Solutions, Inc. + * + * SPDX-License-Identifier: LGPL-2.0+ + */ + +#ifndef __OS_SUPPORT_H_ +#define __OS_SUPPORT_H_ + +#include "compiler.h" + +/* + * Include additional files required for supporting different operating systems + */ +#ifdef __MINGW32__ +#include "mingw_support.h" +#endif + +#if defined(__APPLE__) && __DARWIN_C_LEVEL < 200809L +#include "getline.h" +#endif + +#endif /* __OS_SUPPORT_H_ */ diff --git a/qemu/roms/u-boot/tools/palmtreo680/flash_u-boot.c b/qemu/roms/u-boot/tools/palmtreo680/flash_u-boot.c new file mode 100644 index 000000000..3d8296fc6 --- /dev/null +++ b/qemu/roms/u-boot/tools/palmtreo680/flash_u-boot.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + * + * + * This is a userspace Linux utility that, when run on the Treo 680, will + * program u-boot to flash. The docg4 driver *must* be loaded with the + * reliable_mode and ignore_badblocks parameters enabled: + * + * modprobe docg4 ignore_badblocks=1 reliable_mode=1 + * + * This utility writes the concatenated spl + u-boot image to the start of the + * mtd device in the format expected by the IPL/SPL. The image file and mtd + * device node are passed to the utility as arguments. The blocks must have + * been erased beforehand. + * + * When you compile this, note that it links to libmtd from mtd-utils, so ensure + * that your include and lib paths include this. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include <mtd/mtd-user.h> +#include "libmtd.h" + +#define RELIABLE_BLOCKSIZE 0x10000 /* block capacity in reliable mode */ +#define STANDARD_BLOCKSIZE 0x40000 /* block capacity in normal mode */ +#define PAGESIZE 512 +#define PAGES_PER_BLOCK 512 +#define OOBSIZE 7 /* available to user (16 total) */ + +uint8_t ff_oob[OOBSIZE] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +/* this is the magic number the IPL looks for (ASCII "BIPO") */ +uint8_t page0_oob[OOBSIZE] = {'B', 'I', 'P', 'O', 0xff, 0xff, 0xff}; + +int main(int argc, char * const argv[]) +{ + int devfd, datafd, num_blocks, block; + off_t file_size; + libmtd_t mtd_desc; + struct mtd_dev_info devinfo; + uint8_t *blockbuf; + char response[8]; + + if (argc != 3) { + printf("usage: %s <image file> <mtd dev node>\n", argv[0]); + return -EINVAL; + } + + mtd_desc = libmtd_open(); + if (mtd_desc == NULL) { + int errsv = errno; + fprintf(stderr, "can't initialize libmtd\n"); + return -errsv; + } + + /* open the spl image file and mtd device */ + datafd = open(argv[1], O_RDONLY); + if (datafd == -1) { + int errsv = errno; + perror(argv[1]); + return -errsv; + } + devfd = open(argv[2], O_WRONLY); + if (devfd == -1) { + int errsv = errno; + perror(argv[2]); + return -errsv; + } + if (mtd_get_dev_info(mtd_desc, argv[2], &devinfo) < 0) { + int errsv = errno; + perror(argv[2]); + return -errsv; + } + + /* determine the number of blocks needed by the image */ + file_size = lseek(datafd, 0, SEEK_END); + if (file_size == (off_t)-1) { + int errsv = errno; + perror("lseek"); + return -errsv; + } + num_blocks = (file_size + RELIABLE_BLOCKSIZE - 1) / RELIABLE_BLOCKSIZE; + file_size = lseek(datafd, 0, SEEK_SET); + if (file_size == (off_t)-1) { + int errsv = errno; + perror("lseek"); + return -errsv; + } + printf("The mtd partition contains %d blocks\n", devinfo.eb_cnt); + printf("U-boot will occupy %d blocks\n", num_blocks); + if (num_blocks > devinfo.eb_cnt) { + fprintf(stderr, "Insufficient blocks on partition\n"); + return -EINVAL; + } + + printf("IMPORTANT: These blocks must be in an erased state!\n"); + printf("Do you want to proceed?\n"); + scanf("%s", response); + if ((response[0] != 'y') && (response[0] != 'Y')) { + printf("Exiting\n"); + close(devfd); + close(datafd); + return 0; + } + + blockbuf = calloc(RELIABLE_BLOCKSIZE, 1); + if (blockbuf == NULL) { + int errsv = errno; + perror("calloc"); + return -errsv; + } + + for (block = 0; block < num_blocks; block++) { + int ofs, page; + uint8_t *pagebuf = blockbuf, *buf = blockbuf; + uint8_t *oobbuf = page0_oob; /* magic num in oob of 1st page */ + size_t len = RELIABLE_BLOCKSIZE; + int ret; + + /* read data for one block from file */ + while (len) { + ssize_t read_ret = read(datafd, buf, len); + if (read_ret == -1) { + int errsv = errno; + if (errno == EINTR) + continue; + perror("read"); + return -errsv; + } else if (read_ret == 0) { + break; /* EOF */ + } + len -= read_ret; + buf += read_ret; + } + + printf("Block %d: writing\r", block + 1); + fflush(stdout); + + for (page = 0, ofs = 0; + page < PAGES_PER_BLOCK; + page++, ofs += PAGESIZE) { + if (page & 0x04) /* Odd-numbered 2k page */ + continue; /* skipped in reliable mode */ + + ret = mtd_write(mtd_desc, &devinfo, devfd, block, ofs, + pagebuf, PAGESIZE, oobbuf, OOBSIZE, + MTD_OPS_PLACE_OOB); + if (ret) { + fprintf(stderr, + "\nmtd_write returned %d on block %d, ofs %x\n", + ret, block + 1, ofs); + return -EIO; + } + oobbuf = ff_oob; /* oob for subsequent pages */ + + if (page & 0x01) /* odd-numbered subpage */ + pagebuf += PAGESIZE; + } + } + + printf("\nDone\n"); + + close(devfd); + close(datafd); + free(blockbuf); + return 0; +} diff --git a/qemu/roms/u-boot/tools/patman/.gitignore b/qemu/roms/u-boot/tools/patman/.gitignore new file mode 100644 index 000000000..0d20b6487 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/qemu/roms/u-boot/tools/patman/README b/qemu/roms/u-boot/tools/patman/README new file mode 100644 index 000000000..5fb508b80 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/README @@ -0,0 +1,468 @@ +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +What is this? +============= + +This tool is a Python script which: +- Creates patch directly from your branch +- Cleans them up by removing unwanted tags +- Inserts a cover letter with change lists +- Runs the patches through checkpatch.pl and its own checks +- Optionally emails them out to selected people + +It is intended to automate patch creation and make it a less +error-prone process. It is useful for U-Boot and Linux work so far, +since it uses the checkpatch.pl script. + +It is configured almost entirely by tags it finds in your commits. +This means that you can work on a number of different branches at +once, and keep the settings with each branch rather than having to +git format-patch, git send-email, etc. with the correct parameters +each time. So for example if you put: + +Series-to: fred.blogs@napier.co.nz + +in one of your commits, the series will be sent there. + +In Linux this will also call get_maintainer.pl on each of your +patches automatically. + + +How to use this tool +==================== + +This tool requires a certain way of working: + +- Maintain a number of branches, one for each patch series you are +working on +- Add tags into the commits within each branch to indicate where the +series should be sent, cover letter, version, etc. Most of these are +normally in the top commit so it is easy to change them with 'git +commit --amend' +- Each branch tracks the upstream branch, so that this script can +automatically determine the number of commits in it (optional) +- Check out a branch, and run this script to create and send out your +patches. Weeks later, change the patches and repeat, knowing that you +will get a consistent result each time. + + +How to configure it +=================== + +For most cases of using patman for U-Boot development, patman will +locate and use the file 'doc/git-mailrc' in your U-Boot directory. +This contains most of the aliases you will need. + +For Linux the 'scripts/get_maintainer.pl' handles figuring out where +to send patches pretty well. + +During the first run patman creates a config file for you by taking the default +user name and email address from the global .gitconfig file. + +To add your own, create a file ~/.patman like this: + +>>>> +# patman alias file + +[alias] +me: Simon Glass <sjg@chromium.org> + +u-boot: U-Boot Mailing List <u-boot@lists.denx.de> +wolfgang: Wolfgang Denk <wd@denx.de> +others: Mike Frysinger <vapier@gentoo.org>, Fred Bloggs <f.bloggs@napier.net> + +<<<< + +Aliases are recursive. + +The checkpatch.pl in the U-Boot tools/ subdirectory will be located and +used. Failing that you can put it into your path or ~/bin/checkpatch.pl + + +If you want to change the defaults for patman's command-line arguments, +you can add a [settings] section to your .patman file. This can be used +for any command line option by referring to the "dest" for the option in +patman.py. For reference, the useful ones (at the moment) shown below +(all with the non-default setting): + +>>> + +[settings] +ignore_errors: True +process_tags: False +verbose: True + +<<< + + +If you want to adjust settings (or aliases) that affect just a single +project you can add a section that looks like [project_settings] or +[project_alias]. If you want to use tags for your linux work, you could +do: + +>>> + +[linux_settings] +process_tags: True + +<<< + + +How to run it +============= + +First do a dry run: + +$ ./tools/patman/patman -n + +If it can't detect the upstream branch, try telling it how many patches +there are in your series: + +$ ./tools/patman/patman -n -c5 + +This will create patch files in your current directory and tell you who +it is thinking of sending them to. Take a look at the patch files. + +$ ./tools/patman/patman -n -c5 -s1 + +Similar to the above, but skip the first commit and take the next 5. This +is useful if your top commit is for setting up testing. + + +How to add tags +=============== + +To make this script useful you must add tags like the following into any +commit. Most can only appear once in the whole series. + +Series-to: email / alias + Email address / alias to send patch series to (you can add this + multiple times) + +Series-cc: email / alias, ... + Email address / alias to Cc patch series to (you can add this + multiple times) + +Series-version: n + Sets the version number of this patch series + +Series-prefix: prefix + Sets the subject prefix. Normally empty but it can be RFC for + RFC patches, or RESEND if you are being ignored. + +Series-name: name + Sets the name of the series. You don't need to have a name, and + patman does not yet use it, but it is convenient to put the branch + name here to help you keep track of multiple upstreaming efforts. + +Cover-letter: +This is the patch set title +blah blah +more blah blah +END + Sets the cover letter contents for the series. The first line + will become the subject of the cover letter + +Cover-letter-cc: email / alias + Additional email addresses / aliases to send cover letter to (you + can add this multiple times) + +Series-notes: +blah blah +blah blah +more blah blah +END + Sets some notes for the patch series, which you don't want in + the commit messages, but do want to send, The notes are joined + together and put after the cover letter. Can appear multiple + times. + +Commit-notes: +blah blah +blah blah +more blah blah +END + Similar, but for a single commit (patch). These notes will appear + immediately below the --- cut in the patch file. + + Signed-off-by: Their Name <email> + A sign-off is added automatically to your patches (this is + probably a bug). If you put this tag in your patches, it will + override the default signoff that patman automatically adds. + Multiple duplicate signoffs will be removed. + + Tested-by: Their Name <email> + Reviewed-by: Their Name <email> + Acked-by: Their Name <email> + These indicate that someone has tested/reviewed/acked your patch. + When you get this reply on the mailing list, you can add this + tag to the relevant commit and the script will include it when + you send out the next version. If 'Tested-by:' is set to + yourself, it will be removed. No one will believe you. + +Series-changes: n +- Guinea pig moved into its cage +- Other changes ending with a blank line +<blank line> + This can appear in any commit. It lists the changes for a + particular version n of that commit. The change list is + created based on this information. Each commit gets its own + change list and also the whole thing is repeated in the cover + letter (where duplicate change lines are merged). + + By adding your change lists into your commits it is easier to + keep track of what happened. When you amend a commit, remember + to update the log there and then, knowing that the script will + do the rest. + +Patch-cc: Their Name <email> + This copies a single patch to another email address. Note that the + Cc: used by git send-email is ignored by patman, but will be + interpreted by git send-email if you use it. + +Series-process-log: sort, uniq + This tells patman to sort and/or uniq the change logs. It is + assumed that each change log entry is only a single line long. + Use 'sort' to sort the entries, and 'uniq' to include only + unique entries. If omitted, no change log processing is done. + Separate each tag with a comma. + +Various other tags are silently removed, like these Chrome OS and +Gerrit tags: + +BUG=... +TEST=... +Change-Id: +Review URL: +Reviewed-on: +Commit-xxxx: (except Commit-notes) + +Exercise for the reader: Try adding some tags to one of your current +patch series and see how the patches turn out. + + +Where Patches Are Sent +====================== + +Once the patches are created, patman sends them using git send-email. The +whole series is sent to the recipients in Series-to: and Series-cc. +You can Cc individual patches to other people with the Patch-cc: tag. Tags +in the subject are also picked up to Cc patches. For example, a commit like +this: + +>>>> +commit 10212537b85ff9b6e09c82045127522c0f0db981 +Author: Mike Frysinger <vapier@gentoo.org> +Date: Mon Nov 7 23:18:44 2011 -0500 + + x86: arm: add a git mailrc file for maintainers + + This should make sending out e-mails to the right people easier. + + Patch-cc: sandbox, mikef, ag + Patch-cc: afleming +<<<< + +will create a patch which is copied to x86, arm, sandbox, mikef, ag and +afleming. + +If you have a cover letter it will get sent to the union of the Patch-cc +lists of all of the other patches. If you want to sent it to additional +people you can add a tag: + +Cover-letter-cc: <list of addresses> + +These people will get the cover letter even if they are not on the To/Cc +list for any of the patches. + + +Example Work Flow +================= + +The basic workflow is to create your commits, add some tags to the top +commit, and type 'patman' to check and send them. + +Here is an example workflow for a series of 4 patches. Let's say you have +these rather contrived patches in the following order in branch us-cmd in +your tree where 'us' means your upstreaming activity (newest to oldest as +output by git log --oneline): + + 7c7909c wip + 89234f5 Don't include standard parser if hush is used + 8d640a7 mmc: sparc: Stop using builtin_run_command() + 0c859a9 Rename run_command2() to run_command() + a74443f sandbox: Rename run_command() to builtin_run_command() + +The first patch is some test things that enable your code to be compiled, +but that you don't want to submit because there is an existing patch for it +on the list. So you can tell patman to create and check some patches +(skipping the first patch) with: + + patman -s1 -n + +If you want to do all of them including the work-in-progress one, then +(if you are tracking an upstream branch): + + patman -n + +Let's say that patman reports an error in the second patch. Then: + + git rebase -i HEAD~6 + <change 'pick' to 'edit' in 89234f5> + <use editor to make code changes> + git add -u + git rebase --continue + +Now you have an updated patch series. To check it: + + patman -s1 -n + +Let's say it is now clean and you want to send it. Now you need to set up +the destination. So amend the top commit with: + + git commit --amend + +Use your editor to add some tags, so that the whole commit message is: + + The current run_command() is really only one of the options, with + hush providing the other. It really shouldn't be called directly + in case the hush parser is bring used, so rename this function to + better explain its purpose. + + Series-to: u-boot + Series-cc: bfin, marex + Series-prefix: RFC + Cover-letter: + Unified command execution in one place + + At present two parsers have similar code to execute commands. Also + cmd_usage() is called all over the place. This series adds a single + function which processes commands called cmd_process(). + END + + Change-Id: Ica71a14c1f0ecb5650f771a32fecb8d2eb9d8a17 + + +You want this to be an RFC and Cc the whole series to the bfin alias and +to Marek. Two of the patches have tags (those are the bits at the front of +the subject that say mmc: sparc: and sandbox:), so 8d640a7 will be Cc'd to +mmc and sparc, and the last one to sandbox. + +Now to send the patches, take off the -n flag: + + patman -s1 + +The patches will be created, shown in your editor, and then sent along with +the cover letter. Note that patman's tags are automatically removed so that +people on the list don't see your secret info. + +Of course patches often attract comments and you need to make some updates. +Let's say one person sent comments and you get an Acked-by: on one patch. +Also, the patch on the list that you were waiting for has been merged, +so you can drop your wip commit. So you resync with upstream: + + git fetch origin (or whatever upstream is called) + git rebase origin/master + +and use git rebase -i to edit the commits, dropping the wip one. You add +the ack tag to one commit: + + Acked-by: Heiko Schocher <hs@denx.de> + +update the Series-cc: in the top commit: + + Series-cc: bfin, marex, Heiko Schocher <hs@denx.de> + +and remove the Series-prefix: tag since it it isn't an RFC any more. The +series is now version two, so the series info in the top commit looks like +this: + + Series-to: u-boot + Series-cc: bfin, marex, Heiko Schocher <hs@denx.de> + Series-version: 2 + Cover-letter: + ... + +Finally, you need to add a change log to the two commits you changed. You +add change logs to each individual commit where the changes happened, like +this: + + Series-changes: 2 + - Updated the command decoder to reduce code size + - Wound the torque propounder up a little more + +(note the blank line at the end of the list) + +When you run patman it will collect all the change logs from the different +commits and combine them into the cover letter, if you have one. So finally +you have a new series of commits: + + faeb973 Don't include standard parser if hush is used + 1b2f2fe mmc: sparc: Stop using builtin_run_command() + cfbe330 Rename run_command2() to run_command() + 0682677 sandbox: Rename run_command() to builtin_run_command() + +so to send them: + + patman + +and it will create and send the version 2 series. + +General points: + +1. When you change back to the us-cmd branch days or weeks later all your +information is still there, safely stored in the commits. You don't need +to remember what version you are up to, who you sent the last lot of patches +to, or anything about the change logs. + +2. If you put tags in the subject, patman will Cc the maintainers +automatically in many cases. + +3. If you want to keep the commits from each series you sent so that you can +compare change and see what you did, you can either create a new branch for +each version, or just tag the branch before you start changing it: + + git tag sent/us-cmd-rfc + ...later... + git tag sent/us-cmd-v2 + +4. If you want to modify the patches a little before sending, you can do +this in your editor, but be careful! + +5. If you want to run git send-email yourself, use the -n flag which will +print out the command line patman would have used. + +6. It is a good idea to add the change log info as you change the commit, +not later when you can't remember which patch you changed. You can always +go back and change or remove logs from commits. + + +Other thoughts +============== + +This script has been split into sensible files but still needs work. +Most of these are indicated by a TODO in the code. + +It would be nice if this could handle the In-reply-to side of things. + +The tests are incomplete, as is customary. Use the --test flag to run them, +and make sure you are in the tools/patman directory first: + + $ cd /path/to/u-boot + $ cd tools/patman + $ ./patman --test + +Error handling doesn't always produce friendly error messages - e.g. +putting an incorrect tag in a commit may provide a confusing message. + +There might be a few other features not mentioned in this README. They +might be bugs. In particular, tags are case sensitive which is probably +a bad thing. + + +Simon Glass <sjg@chromium.org> +v1, v2, 19-Oct-11 +revised v3 24-Nov-11 diff --git a/qemu/roms/u-boot/tools/patman/checkpatch.py b/qemu/roms/u-boot/tools/patman/checkpatch.py new file mode 100644 index 000000000..0d4e93524 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/checkpatch.py @@ -0,0 +1,174 @@ +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import collections +import command +import gitutil +import os +import re +import sys +import terminal + +def FindCheckPatch(): + top_level = gitutil.GetTopLevel() + try_list = [ + os.getcwd(), + os.path.join(os.getcwd(), '..', '..'), + os.path.join(top_level, 'tools'), + os.path.join(top_level, 'scripts'), + '%s/bin' % os.getenv('HOME'), + ] + # Look in current dir + for path in try_list: + fname = os.path.join(path, 'checkpatch.pl') + if os.path.isfile(fname): + return fname + + # Look upwwards for a Chrome OS tree + while not os.path.ismount(path): + fname = os.path.join(path, 'src', 'third_party', 'kernel', 'files', + 'scripts', 'checkpatch.pl') + if os.path.isfile(fname): + return fname + path = os.path.dirname(path) + + print >> sys.stderr, ('Cannot find checkpatch.pl - please put it in your ' + + '~/bin directory or use --no-check') + sys.exit(1) + +def CheckPatch(fname, verbose=False): + """Run checkpatch.pl on a file. + + Returns: + namedtuple containing: + ok: False=failure, True=ok + problems: List of problems, each a dict: + 'type'; error or warning + 'msg': text message + 'file' : filename + 'line': line number + errors: Number of errors + warnings: Number of warnings + checks: Number of checks + lines: Number of lines + stdout: Full output of checkpatch + """ + fields = ['ok', 'problems', 'errors', 'warnings', 'checks', 'lines', + 'stdout'] + result = collections.namedtuple('CheckPatchResult', fields) + result.ok = False + result.errors, result.warning, result.checks = 0, 0, 0 + result.lines = 0 + result.problems = [] + chk = FindCheckPatch() + item = {} + result.stdout = command.Output(chk, '--no-tree', fname) + #pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE) + #stdout, stderr = pipe.communicate() + + # total: 0 errors, 0 warnings, 159 lines checked + # or: + # total: 0 errors, 2 warnings, 7 checks, 473 lines checked + re_stats = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)') + re_stats_full = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)' + ' checks, (\d+)') + re_ok = re.compile('.*has no obvious style problems') + re_bad = re.compile('.*has style problems, please review') + re_error = re.compile('ERROR: (.*)') + re_warning = re.compile('WARNING: (.*)') + re_check = re.compile('CHECK: (.*)') + re_file = re.compile('#\d+: FILE: ([^:]*):(\d+):') + + for line in result.stdout.splitlines(): + if verbose: + print line + + # A blank line indicates the end of a message + if not line and item: + result.problems.append(item) + item = {} + match = re_stats_full.match(line) + if not match: + match = re_stats.match(line) + if match: + result.errors = int(match.group(1)) + result.warnings = int(match.group(2)) + if len(match.groups()) == 4: + result.checks = int(match.group(3)) + result.lines = int(match.group(4)) + else: + result.lines = int(match.group(3)) + elif re_ok.match(line): + result.ok = True + elif re_bad.match(line): + result.ok = False + err_match = re_error.match(line) + warn_match = re_warning.match(line) + file_match = re_file.match(line) + check_match = re_check.match(line) + if err_match: + item['msg'] = err_match.group(1) + item['type'] = 'error' + elif warn_match: + item['msg'] = warn_match.group(1) + item['type'] = 'warning' + elif check_match: + item['msg'] = check_match.group(1) + item['type'] = 'check' + elif file_match: + item['file'] = file_match.group(1) + item['line'] = int(file_match.group(2)) + + return result + +def GetWarningMsg(col, msg_type, fname, line, msg): + '''Create a message for a given file/line + + Args: + msg_type: Message type ('error' or 'warning') + fname: Filename which reports the problem + line: Line number where it was noticed + msg: Message to report + ''' + if msg_type == 'warning': + msg_type = col.Color(col.YELLOW, msg_type) + elif msg_type == 'error': + msg_type = col.Color(col.RED, msg_type) + elif msg_type == 'check': + msg_type = col.Color(col.MAGENTA, msg_type) + return '%s: %s,%d: %s' % (msg_type, fname, line, msg) + +def CheckPatches(verbose, args): + '''Run the checkpatch.pl script on each patch''' + error_count, warning_count, check_count = 0, 0, 0 + col = terminal.Color() + + for fname in args: + result = CheckPatch(fname, verbose) + if not result.ok: + error_count += result.errors + warning_count += result.warnings + check_count += result.checks + print '%d errors, %d warnings, %d checks for %s:' % (result.errors, + result.warnings, result.checks, col.Color(col.BLUE, fname)) + if (len(result.problems) != result.errors + result.warnings + + result.checks): + print "Internal error: some problems lost" + for item in result.problems: + print GetWarningMsg(col, item.get('type', '<unknown>'), + item.get('file', '<unknown>'), + item.get('line', 0), item.get('msg', 'message')) + print + #print stdout + if error_count or warning_count or check_count: + str = 'checkpatch.pl found %d error(s), %d warning(s), %d checks(s)' + color = col.GREEN + if warning_count: + color = col.YELLOW + if error_count: + color = col.RED + print col.Color(color, str % (error_count, warning_count, check_count)) + return False + return True diff --git a/qemu/roms/u-boot/tools/patman/command.py b/qemu/roms/u-boot/tools/patman/command.py new file mode 100644 index 000000000..449d3d0e0 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/command.py @@ -0,0 +1,101 @@ +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import os +import cros_subprocess + +"""Shell command ease-ups for Python.""" + +class CommandResult: + """A class which captures the result of executing a command. + + Members: + stdout: stdout obtained from command, as a string + stderr: stderr obtained from command, as a string + return_code: Return code from command + exception: Exception received, or None if all ok + """ + def __init__(self): + self.stdout = None + self.stderr = None + self.return_code = None + self.exception = None + + +def RunPipe(pipe_list, infile=None, outfile=None, + capture=False, capture_stderr=False, oneline=False, + raise_on_error=True, cwd=None, **kwargs): + """ + Perform a command pipeline, with optional input/output filenames. + + Args: + pipe_list: List of command lines to execute. Each command line is + piped into the next, and is itself a list of strings. For + example [ ['ls', '.git'] ['wc'] ] will pipe the output of + 'ls .git' into 'wc'. + infile: File to provide stdin to the pipeline + outfile: File to store stdout + capture: True to capture output + capture_stderr: True to capture stderr + oneline: True to strip newline chars from output + kwargs: Additional keyword arguments to cros_subprocess.Popen() + Returns: + CommandResult object + """ + result = CommandResult() + last_pipe = None + pipeline = list(pipe_list) + user_pipestr = '|'.join([' '.join(pipe) for pipe in pipe_list]) + while pipeline: + cmd = pipeline.pop(0) + if last_pipe is not None: + kwargs['stdin'] = last_pipe.stdout + elif infile: + kwargs['stdin'] = open(infile, 'rb') + if pipeline or capture: + kwargs['stdout'] = cros_subprocess.PIPE + elif outfile: + kwargs['stdout'] = open(outfile, 'wb') + if capture_stderr: + kwargs['stderr'] = cros_subprocess.PIPE + + try: + last_pipe = cros_subprocess.Popen(cmd, cwd=cwd, **kwargs) + except Exception, err: + result.exception = err + if raise_on_error: + raise Exception("Error running '%s': %s" % (user_pipestr, str)) + result.return_code = 255 + return result + + if capture: + result.stdout, result.stderr, result.combined = ( + last_pipe.CommunicateFilter(None)) + if result.stdout and oneline: + result.output = result.stdout.rstrip('\r\n') + result.return_code = last_pipe.wait() + else: + result.return_code = os.waitpid(last_pipe.pid, 0)[1] + if raise_on_error and result.return_code: + raise Exception("Error running '%s'" % user_pipestr) + return result + +def Output(*cmd): + return RunPipe([cmd], capture=True, raise_on_error=False).stdout + +def OutputOneLine(*cmd, **kwargs): + raise_on_error = kwargs.pop('raise_on_error', True) + return (RunPipe([cmd], capture=True, oneline=True, + raise_on_error=raise_on_error, + **kwargs).stdout.strip()) + +def Run(*cmd, **kwargs): + return RunPipe([cmd], **kwargs).stdout + +def RunList(cmd): + return RunPipe([cmd], capture=True).stdout + +def StopAll(): + cros_subprocess.stay_alive = False diff --git a/qemu/roms/u-boot/tools/patman/commit.py b/qemu/roms/u-boot/tools/patman/commit.py new file mode 100644 index 000000000..3e0adb8f7 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/commit.py @@ -0,0 +1,88 @@ +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import re + +# Separates a tag: at the beginning of the subject from the rest of it +re_subject_tag = re.compile('([^:\s]*):\s*(.*)') + +class Commit: + """Holds information about a single commit/patch in the series. + + Args: + hash: Commit hash (as a string) + + Variables: + hash: Commit hash + subject: Subject line + tags: List of maintainer tag strings + changes: Dict containing a list of changes (single line strings). + The dict is indexed by change version (an integer) + cc_list: List of people to aliases/emails to cc on this commit + notes: List of lines in the commit (not series) notes + """ + def __init__(self, hash): + self.hash = hash + self.subject = None + self.tags = [] + self.changes = {} + self.cc_list = [] + self.signoff_set = set() + self.notes = [] + + def AddChange(self, version, info): + """Add a new change line to the change list for a version. + + Args: + version: Patch set version (integer: 1, 2, 3) + info: Description of change in this version + """ + if not self.changes.get(version): + self.changes[version] = [] + self.changes[version].append(info) + + def CheckTags(self): + """Create a list of subject tags in the commit + + Subject tags look like this: + + propounder: fort: Change the widget to propound correctly + + Here the tags are propounder and fort. Multiple tags are supported. + The list is updated in self.tag. + + Returns: + None if ok, else the name of a tag with no email alias + """ + str = self.subject + m = True + while m: + m = re_subject_tag.match(str) + if m: + tag = m.group(1) + self.tags.append(tag) + str = m.group(2) + return None + + def AddCc(self, cc_list): + """Add a list of people to Cc when we send this patch. + + Args: + cc_list: List of aliases or email addresses + """ + self.cc_list += cc_list + + def CheckDuplicateSignoff(self, signoff): + """Check a list of signoffs we have send for this patch + + Args: + signoff: Signoff line + Returns: + True if this signoff is new, False if we have already seen it. + """ + if signoff in self.signoff_set: + return False + self.signoff_set.add(signoff) + return True diff --git a/qemu/roms/u-boot/tools/patman/cros_subprocess.py b/qemu/roms/u-boot/tools/patman/cros_subprocess.py new file mode 100644 index 000000000..0fc4a06b5 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/cros_subprocess.py @@ -0,0 +1,397 @@ +# Copyright (c) 2012 The Chromium OS Authors. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Copyright (c) 2003-2005 by Peter Astrand <astrand@lysator.liu.se> +# Licensed to PSF under a Contributor Agreement. +# See http://www.python.org/2.4/license for licensing details. + +"""Subprocress execution + +This module holds a subclass of subprocess.Popen with our own required +features, mainly that we get access to the subprocess output while it +is running rather than just at the end. This makes it easiler to show +progress information and filter output in real time. +""" + +import errno +import os +import pty +import select +import subprocess +import sys +import unittest + + +# Import these here so the caller does not need to import subprocess also. +PIPE = subprocess.PIPE +STDOUT = subprocess.STDOUT +PIPE_PTY = -3 # Pipe output through a pty +stay_alive = True + + +class Popen(subprocess.Popen): + """Like subprocess.Popen with ptys and incremental output + + This class deals with running a child process and filtering its output on + both stdout and stderr while it is running. We do this so we can monitor + progress, and possibly relay the output to the user if requested. + + The class is similar to subprocess.Popen, the equivalent is something like: + + Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + But this class has many fewer features, and two enhancement: + + 1. Rather than getting the output data only at the end, this class sends it + to a provided operation as it arrives. + 2. We use pseudo terminals so that the child will hopefully flush its output + to us as soon as it is produced, rather than waiting for the end of a + line. + + Use CommunicateFilter() to handle output from the subprocess. + + """ + + def __init__(self, args, stdin=None, stdout=PIPE_PTY, stderr=PIPE_PTY, + shell=False, cwd=None, env=None, **kwargs): + """Cut-down constructor + + Args: + args: Program and arguments for subprocess to execute. + stdin: See subprocess.Popen() + stdout: See subprocess.Popen(), except that we support the sentinel + value of cros_subprocess.PIPE_PTY. + stderr: See subprocess.Popen(), except that we support the sentinel + value of cros_subprocess.PIPE_PTY. + shell: See subprocess.Popen() + cwd: Working directory to change to for subprocess, or None if none. + env: Environment to use for this subprocess, or None to inherit parent. + kwargs: No other arguments are supported at the moment. Passing other + arguments will cause a ValueError to be raised. + """ + stdout_pty = None + stderr_pty = None + + if stdout == PIPE_PTY: + stdout_pty = pty.openpty() + stdout = os.fdopen(stdout_pty[1]) + if stderr == PIPE_PTY: + stderr_pty = pty.openpty() + stderr = os.fdopen(stderr_pty[1]) + + super(Popen, self).__init__(args, stdin=stdin, + stdout=stdout, stderr=stderr, shell=shell, cwd=cwd, env=env, + **kwargs) + + # If we're on a PTY, we passed the slave half of the PTY to the subprocess. + # We want to use the master half on our end from now on. Setting this here + # does make some assumptions about the implementation of subprocess, but + # those assumptions are pretty minor. + + # Note that if stderr is STDOUT, then self.stderr will be set to None by + # this constructor. + if stdout_pty is not None: + self.stdout = os.fdopen(stdout_pty[0]) + if stderr_pty is not None: + self.stderr = os.fdopen(stderr_pty[0]) + + # Insist that unit tests exist for other arguments we don't support. + if kwargs: + raise ValueError("Unit tests do not test extra args - please add tests") + + def CommunicateFilter(self, output): + """Interact with process: Read data from stdout and stderr. + + This method runs until end-of-file is reached, then waits for the + subprocess to terminate. + + The output function is sent all output from the subprocess and must be + defined like this: + + def Output([self,] stream, data) + Args: + stream: the stream the output was received on, which will be + sys.stdout or sys.stderr. + data: a string containing the data + + Note: The data read is buffered in memory, so do not use this + method if the data size is large or unlimited. + + Args: + output: Function to call with each fragment of output. + + Returns: + A tuple (stdout, stderr, combined) which is the data received on + stdout, stderr and the combined data (interleaved stdout and stderr). + + Note that the interleaved output will only be sensible if you have + set both stdout and stderr to PIPE or PIPE_PTY. Even then it depends on + the timing of the output in the subprocess. If a subprocess flips + between stdout and stderr quickly in succession, by the time we come to + read the output from each we may see several lines in each, and will read + all the stdout lines, then all the stderr lines. So the interleaving + may not be correct. In this case you might want to pass + stderr=cros_subprocess.STDOUT to the constructor. + + This feature is still useful for subprocesses where stderr is + rarely used and indicates an error. + + Note also that if you set stderr to STDOUT, then stderr will be empty + and the combined output will just be the same as stdout. + """ + + read_set = [] + write_set = [] + stdout = None # Return + stderr = None # Return + + if self.stdin: + # Flush stdio buffer. This might block, if the user has + # been writing to .stdin in an uncontrolled fashion. + self.stdin.flush() + if input: + write_set.append(self.stdin) + else: + self.stdin.close() + if self.stdout: + read_set.append(self.stdout) + stdout = [] + if self.stderr and self.stderr != self.stdout: + read_set.append(self.stderr) + stderr = [] + combined = [] + + input_offset = 0 + while read_set or write_set: + try: + rlist, wlist, _ = select.select(read_set, write_set, [], 0.2) + except select.error, e: + if e.args[0] == errno.EINTR: + continue + raise + + if not stay_alive: + self.terminate() + + if self.stdin in wlist: + # When select has indicated that the file is writable, + # we can write up to PIPE_BUF bytes without risk + # blocking. POSIX defines PIPE_BUF >= 512 + chunk = input[input_offset : input_offset + 512] + bytes_written = os.write(self.stdin.fileno(), chunk) + input_offset += bytes_written + if input_offset >= len(input): + self.stdin.close() + write_set.remove(self.stdin) + + if self.stdout in rlist: + data = "" + # We will get an error on read if the pty is closed + try: + data = os.read(self.stdout.fileno(), 1024) + except OSError: + pass + if data == "": + self.stdout.close() + read_set.remove(self.stdout) + else: + stdout.append(data) + combined.append(data) + if output: + output(sys.stdout, data) + if self.stderr in rlist: + data = "" + # We will get an error on read if the pty is closed + try: + data = os.read(self.stderr.fileno(), 1024) + except OSError: + pass + if data == "": + self.stderr.close() + read_set.remove(self.stderr) + else: + stderr.append(data) + combined.append(data) + if output: + output(sys.stderr, data) + + # All data exchanged. Translate lists into strings. + if stdout is not None: + stdout = ''.join(stdout) + else: + stdout = '' + if stderr is not None: + stderr = ''.join(stderr) + else: + stderr = '' + combined = ''.join(combined) + + # Translate newlines, if requested. We cannot let the file + # object do the translation: It is based on stdio, which is + # impossible to combine with select (unless forcing no + # buffering). + if self.universal_newlines and hasattr(file, 'newlines'): + if stdout: + stdout = self._translate_newlines(stdout) + if stderr: + stderr = self._translate_newlines(stderr) + + self.wait() + return (stdout, stderr, combined) + + +# Just being a unittest.TestCase gives us 14 public methods. Unless we +# disable this, we can only have 6 tests in a TestCase. That's not enough. +# +# pylint: disable=R0904 + +class TestSubprocess(unittest.TestCase): + """Our simple unit test for this module""" + + class MyOperation: + """Provides a operation that we can pass to Popen""" + def __init__(self, input_to_send=None): + """Constructor to set up the operation and possible input. + + Args: + input_to_send: a text string to send when we first get input. We will + add \r\n to the string. + """ + self.stdout_data = '' + self.stderr_data = '' + self.combined_data = '' + self.stdin_pipe = None + self._input_to_send = input_to_send + if input_to_send: + pipe = os.pipe() + self.stdin_read_pipe = pipe[0] + self._stdin_write_pipe = os.fdopen(pipe[1], 'w') + + def Output(self, stream, data): + """Output handler for Popen. Stores the data for later comparison""" + if stream == sys.stdout: + self.stdout_data += data + if stream == sys.stderr: + self.stderr_data += data + self.combined_data += data + + # Output the input string if we have one. + if self._input_to_send: + self._stdin_write_pipe.write(self._input_to_send + '\r\n') + self._stdin_write_pipe.flush() + + def _BasicCheck(self, plist, oper): + """Basic checks that the output looks sane.""" + self.assertEqual(plist[0], oper.stdout_data) + self.assertEqual(plist[1], oper.stderr_data) + self.assertEqual(plist[2], oper.combined_data) + + # The total length of stdout and stderr should equal the combined length + self.assertEqual(len(plist[0]) + len(plist[1]), len(plist[2])) + + def test_simple(self): + """Simple redirection: Get process list""" + oper = TestSubprocess.MyOperation() + plist = Popen(['ps']).CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + + def test_stderr(self): + """Check stdout and stderr""" + oper = TestSubprocess.MyOperation() + cmd = 'echo fred >/dev/stderr && false || echo bad' + plist = Popen([cmd], shell=True).CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + self.assertEqual(plist [0], 'bad\r\n') + self.assertEqual(plist [1], 'fred\r\n') + + def test_shell(self): + """Check with and without shell works""" + oper = TestSubprocess.MyOperation() + cmd = 'echo test >/dev/stderr' + self.assertRaises(OSError, Popen, [cmd], shell=False) + plist = Popen([cmd], shell=True).CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + self.assertEqual(len(plist [0]), 0) + self.assertEqual(plist [1], 'test\r\n') + + def test_list_args(self): + """Check with and without shell works using list arguments""" + oper = TestSubprocess.MyOperation() + cmd = ['echo', 'test', '>/dev/stderr'] + plist = Popen(cmd, shell=False).CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + self.assertEqual(plist [0], ' '.join(cmd[1:]) + '\r\n') + self.assertEqual(len(plist [1]), 0) + + oper = TestSubprocess.MyOperation() + + # this should be interpreted as 'echo' with the other args dropped + cmd = ['echo', 'test', '>/dev/stderr'] + plist = Popen(cmd, shell=True).CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + self.assertEqual(plist [0], '\r\n') + + def test_cwd(self): + """Check we can change directory""" + for shell in (False, True): + oper = TestSubprocess.MyOperation() + plist = Popen('pwd', shell=shell, cwd='/tmp').CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + self.assertEqual(plist [0], '/tmp\r\n') + + def test_env(self): + """Check we can change environment""" + for add in (False, True): + oper = TestSubprocess.MyOperation() + env = os.environ + if add: + env ['FRED'] = 'fred' + cmd = 'echo $FRED' + plist = Popen(cmd, shell=True, env=env).CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + self.assertEqual(plist [0], add and 'fred\r\n' or '\r\n') + + def test_extra_args(self): + """Check we can't add extra arguments""" + self.assertRaises(ValueError, Popen, 'true', close_fds=False) + + def test_basic_input(self): + """Check that incremental input works + + We set up a subprocess which will prompt for name. When we see this prompt + we send the name as input to the process. It should then print the name + properly to stdout. + """ + oper = TestSubprocess.MyOperation('Flash') + prompt = 'What is your name?: ' + cmd = 'echo -n "%s"; read name; echo Hello $name' % prompt + plist = Popen([cmd], stdin=oper.stdin_read_pipe, + shell=True).CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + self.assertEqual(len(plist [1]), 0) + self.assertEqual(plist [0], prompt + 'Hello Flash\r\r\n') + + def test_isatty(self): + """Check that ptys appear as terminals to the subprocess""" + oper = TestSubprocess.MyOperation() + cmd = ('if [ -t %d ]; then echo "terminal %d" >&%d; ' + 'else echo "not %d" >&%d; fi;') + both_cmds = '' + for fd in (1, 2): + both_cmds += cmd % (fd, fd, fd, fd, fd) + plist = Popen(both_cmds, shell=True).CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + self.assertEqual(plist [0], 'terminal 1\r\n') + self.assertEqual(plist [1], 'terminal 2\r\n') + + # Now try with PIPE and make sure it is not a terminal + oper = TestSubprocess.MyOperation() + plist = Popen(both_cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + shell=True).CommunicateFilter(oper.Output) + self._BasicCheck(plist, oper) + self.assertEqual(plist [0], 'not 1\n') + self.assertEqual(plist [1], 'not 2\n') + +if __name__ == '__main__': + unittest.main() diff --git a/qemu/roms/u-boot/tools/patman/get_maintainer.py b/qemu/roms/u-boot/tools/patman/get_maintainer.py new file mode 100644 index 000000000..00b49394b --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/get_maintainer.py @@ -0,0 +1,47 @@ +# Copyright (c) 2012 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import command +import gitutil +import os + +def FindGetMaintainer(): + """Look for the get_maintainer.pl script. + + Returns: + If the script is found we'll return a path to it; else None. + """ + try_list = [ + os.path.join(gitutil.GetTopLevel(), 'scripts'), + ] + # Look in the list + for path in try_list: + fname = os.path.join(path, 'get_maintainer.pl') + if os.path.isfile(fname): + return fname + + return None + +def GetMaintainer(fname, verbose=False): + """Run get_maintainer.pl on a file if we find it. + + We look for get_maintainer.pl in the 'scripts' directory at the top of + git. If we find it we'll run it. If we don't find get_maintainer.pl + then we fail silently. + + Args: + fname: Path to the patch file to run get_maintainer.pl on. + + Returns: + A list of email addresses to CC to. + """ + get_maintainer = FindGetMaintainer() + if not get_maintainer: + if verbose: + print "WARNING: Couldn't find get_maintainer.pl" + return [] + + stdout = command.Output(get_maintainer, '--norolestats', fname) + return stdout.splitlines() diff --git a/qemu/roms/u-boot/tools/patman/gitutil.py b/qemu/roms/u-boot/tools/patman/gitutil.py new file mode 100644 index 000000000..3ea256de2 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/gitutil.py @@ -0,0 +1,549 @@ +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import command +import re +import os +import series +import subprocess +import sys +import terminal + +import checkpatch +import settings + + +def CountCommitsToBranch(): + """Returns number of commits between HEAD and the tracking branch. + + This looks back to the tracking branch and works out the number of commits + since then. + + Return: + Number of patches that exist on top of the branch + """ + pipe = [['git', 'log', '--no-color', '--oneline', '--no-decorate', + '@{upstream}..'], + ['wc', '-l']] + stdout = command.RunPipe(pipe, capture=True, oneline=True).stdout + patch_count = int(stdout) + return patch_count + +def GetUpstream(git_dir, branch): + """Returns the name of the upstream for a branch + + Args: + git_dir: Git directory containing repo + branch: Name of branch + + Returns: + Name of upstream branch (e.g. 'upstream/master') or None if none + """ + try: + remote = command.OutputOneLine('git', '--git-dir', git_dir, 'config', + 'branch.%s.remote' % branch) + merge = command.OutputOneLine('git', '--git-dir', git_dir, 'config', + 'branch.%s.merge' % branch) + except: + return None + + if remote == '.': + return merge + elif remote and merge: + leaf = merge.split('/')[-1] + return '%s/%s' % (remote, leaf) + else: + raise ValueError, ("Cannot determine upstream branch for branch " + "'%s' remote='%s', merge='%s'" % (branch, remote, merge)) + + +def GetRangeInBranch(git_dir, branch, include_upstream=False): + """Returns an expression for the commits in the given branch. + + Args: + git_dir: Directory containing git repo + branch: Name of branch + Return: + Expression in the form 'upstream..branch' which can be used to + access the commits. If the branch does not exist, returns None. + """ + upstream = GetUpstream(git_dir, branch) + if not upstream: + return None + return '%s%s..%s' % (upstream, '~' if include_upstream else '', branch) + +def CountCommitsInBranch(git_dir, branch, include_upstream=False): + """Returns the number of commits in the given branch. + + Args: + git_dir: Directory containing git repo + branch: Name of branch + Return: + Number of patches that exist on top of the branch, or None if the + branch does not exist. + """ + range_expr = GetRangeInBranch(git_dir, branch, include_upstream) + if not range_expr: + return None + pipe = [['git', '--git-dir', git_dir, 'log', '--oneline', '--no-decorate', + range_expr], + ['wc', '-l']] + result = command.RunPipe(pipe, capture=True, oneline=True) + patch_count = int(result.stdout) + return patch_count + +def CountCommits(commit_range): + """Returns the number of commits in the given range. + + Args: + commit_range: Range of commits to count (e.g. 'HEAD..base') + Return: + Number of patches that exist on top of the branch + """ + pipe = [['git', 'log', '--oneline', '--no-decorate', commit_range], + ['wc', '-l']] + stdout = command.RunPipe(pipe, capture=True, oneline=True).stdout + patch_count = int(stdout) + return patch_count + +def Checkout(commit_hash, git_dir=None, work_tree=None, force=False): + """Checkout the selected commit for this build + + Args: + commit_hash: Commit hash to check out + """ + pipe = ['git'] + if git_dir: + pipe.extend(['--git-dir', git_dir]) + if work_tree: + pipe.extend(['--work-tree', work_tree]) + pipe.append('checkout') + if force: + pipe.append('-f') + pipe.append(commit_hash) + result = command.RunPipe([pipe], capture=True, raise_on_error=False) + if result.return_code != 0: + raise OSError, 'git checkout (%s): %s' % (pipe, result.stderr) + +def Clone(git_dir, output_dir): + """Checkout the selected commit for this build + + Args: + commit_hash: Commit hash to check out + """ + pipe = ['git', 'clone', git_dir, '.'] + result = command.RunPipe([pipe], capture=True, cwd=output_dir) + if result.return_code != 0: + raise OSError, 'git clone: %s' % result.stderr + +def Fetch(git_dir=None, work_tree=None): + """Fetch from the origin repo + + Args: + commit_hash: Commit hash to check out + """ + pipe = ['git'] + if git_dir: + pipe.extend(['--git-dir', git_dir]) + if work_tree: + pipe.extend(['--work-tree', work_tree]) + pipe.append('fetch') + result = command.RunPipe([pipe], capture=True) + if result.return_code != 0: + raise OSError, 'git fetch: %s' % result.stderr + +def CreatePatches(start, count, series): + """Create a series of patches from the top of the current branch. + + The patch files are written to the current directory using + git format-patch. + + Args: + start: Commit to start from: 0=HEAD, 1=next one, etc. + count: number of commits to include + Return: + Filename of cover letter + List of filenames of patch files + """ + if series.get('version'): + version = '%s ' % series['version'] + cmd = ['git', 'format-patch', '-M', '--signoff'] + if series.get('cover'): + cmd.append('--cover-letter') + prefix = series.GetPatchPrefix() + if prefix: + cmd += ['--subject-prefix=%s' % prefix] + cmd += ['HEAD~%d..HEAD~%d' % (start + count, start)] + + stdout = command.RunList(cmd) + files = stdout.splitlines() + + # We have an extra file if there is a cover letter + if series.get('cover'): + return files[0], files[1:] + else: + return None, files + +def ApplyPatch(verbose, fname): + """Apply a patch with git am to test it + + TODO: Convert these to use command, with stderr option + + Args: + fname: filename of patch file to apply + """ + col = terminal.Color() + cmd = ['git', 'am', fname] + pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = pipe.communicate() + re_error = re.compile('^error: patch failed: (.+):(\d+)') + for line in stderr.splitlines(): + if verbose: + print line + match = re_error.match(line) + if match: + print checkpatch.GetWarningMsg(col, 'warning', match.group(1), + int(match.group(2)), 'Patch failed') + return pipe.returncode == 0, stdout + +def ApplyPatches(verbose, args, start_point): + """Apply the patches with git am to make sure all is well + + Args: + verbose: Print out 'git am' output verbatim + args: List of patch files to apply + start_point: Number of commits back from HEAD to start applying. + Normally this is len(args), but it can be larger if a start + offset was given. + """ + error_count = 0 + col = terminal.Color() + + # Figure out our current position + cmd = ['git', 'name-rev', 'HEAD', '--name-only'] + pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE) + stdout, stderr = pipe.communicate() + if pipe.returncode: + str = 'Could not find current commit name' + print col.Color(col.RED, str) + print stdout + return False + old_head = stdout.splitlines()[0] + + # Checkout the required start point + cmd = ['git', 'checkout', 'HEAD~%d' % start_point] + pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, stderr = pipe.communicate() + if pipe.returncode: + str = 'Could not move to commit before patch series' + print col.Color(col.RED, str) + print stdout, stderr + return False + + # Apply all the patches + for fname in args: + ok, stdout = ApplyPatch(verbose, fname) + if not ok: + print col.Color(col.RED, 'git am returned errors for %s: will ' + 'skip this patch' % fname) + if verbose: + print stdout + error_count += 1 + cmd = ['git', 'am', '--skip'] + pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE) + stdout, stderr = pipe.communicate() + if pipe.returncode != 0: + print col.Color(col.RED, 'Unable to skip patch! Aborting...') + print stdout + break + + # Return to our previous position + cmd = ['git', 'checkout', old_head] + pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = pipe.communicate() + if pipe.returncode: + print col.Color(col.RED, 'Could not move back to head commit') + print stdout, stderr + return error_count == 0 + +def BuildEmailList(in_list, tag=None, alias=None, raise_on_error=True): + """Build a list of email addresses based on an input list. + + Takes a list of email addresses and aliases, and turns this into a list + of only email address, by resolving any aliases that are present. + + If the tag is given, then each email address is prepended with this + tag and a space. If the tag starts with a minus sign (indicating a + command line parameter) then the email address is quoted. + + Args: + in_list: List of aliases/email addresses + tag: Text to put before each address + alias: Alias dictionary + raise_on_error: True to raise an error when an alias fails to match, + False to just print a message. + + Returns: + List of email addresses + + >>> alias = {} + >>> alias['fred'] = ['f.bloggs@napier.co.nz'] + >>> alias['john'] = ['j.bloggs@napier.co.nz'] + >>> alias['mary'] = ['Mary Poppins <m.poppins@cloud.net>'] + >>> alias['boys'] = ['fred', ' john'] + >>> alias['all'] = ['fred ', 'john', ' mary '] + >>> BuildEmailList(['john', 'mary'], None, alias) + ['j.bloggs@napier.co.nz', 'Mary Poppins <m.poppins@cloud.net>'] + >>> BuildEmailList(['john', 'mary'], '--to', alias) + ['--to "j.bloggs@napier.co.nz"', \ +'--to "Mary Poppins <m.poppins@cloud.net>"'] + >>> BuildEmailList(['john', 'mary'], 'Cc', alias) + ['Cc j.bloggs@napier.co.nz', 'Cc Mary Poppins <m.poppins@cloud.net>'] + """ + quote = '"' if tag and tag[0] == '-' else '' + raw = [] + for item in in_list: + raw += LookupEmail(item, alias, raise_on_error=raise_on_error) + result = [] + for item in raw: + if not item in result: + result.append(item) + if tag: + return ['%s %s%s%s' % (tag, quote, email, quote) for email in result] + return result + +def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname, + self_only=False, alias=None, in_reply_to=None): + """Email a patch series. + + Args: + series: Series object containing destination info + cover_fname: filename of cover letter + args: list of filenames of patch files + dry_run: Just return the command that would be run + raise_on_error: True to raise an error when an alias fails to match, + False to just print a message. + cc_fname: Filename of Cc file for per-commit Cc + self_only: True to just email to yourself as a test + in_reply_to: If set we'll pass this to git as --in-reply-to. + Should be a message ID that this is in reply to. + + Returns: + Git command that was/would be run + + # For the duration of this doctest pretend that we ran patman with ./patman + >>> _old_argv0 = sys.argv[0] + >>> sys.argv[0] = './patman' + + >>> alias = {} + >>> alias['fred'] = ['f.bloggs@napier.co.nz'] + >>> alias['john'] = ['j.bloggs@napier.co.nz'] + >>> alias['mary'] = ['m.poppins@cloud.net'] + >>> alias['boys'] = ['fred', ' john'] + >>> alias['all'] = ['fred ', 'john', ' mary '] + >>> alias[os.getenv('USER')] = ['this-is-me@me.com'] + >>> series = series.Series() + >>> series.to = ['fred'] + >>> series.cc = ['mary'] + >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \ + False, alias) + 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \ +"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" cover p1 p2' + >>> EmailPatches(series, None, ['p1'], True, True, 'cc-fname', False, \ + alias) + 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \ +"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" p1' + >>> series.cc = ['all'] + >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \ + True, alias) + 'git send-email --annotate --to "this-is-me@me.com" --cc-cmd "./patman \ +--cc-cmd cc-fname" cover p1 p2' + >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \ + False, alias) + 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \ +"f.bloggs@napier.co.nz" --cc "j.bloggs@napier.co.nz" --cc \ +"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" cover p1 p2' + + # Restore argv[0] since we clobbered it. + >>> sys.argv[0] = _old_argv0 + """ + to = BuildEmailList(series.get('to'), '--to', alias, raise_on_error) + if not to: + print ("No recipient, please add something like this to a commit\n" + "Series-to: Fred Bloggs <f.blogs@napier.co.nz>") + return + cc = BuildEmailList(series.get('cc'), '--cc', alias, raise_on_error) + if self_only: + to = BuildEmailList([os.getenv('USER')], '--to', alias, raise_on_error) + cc = [] + cmd = ['git', 'send-email', '--annotate'] + if in_reply_to: + cmd.append('--in-reply-to="%s"' % in_reply_to) + + cmd += to + cmd += cc + cmd += ['--cc-cmd', '"%s --cc-cmd %s"' % (sys.argv[0], cc_fname)] + if cover_fname: + cmd.append(cover_fname) + cmd += args + str = ' '.join(cmd) + if not dry_run: + os.system(str) + return str + + +def LookupEmail(lookup_name, alias=None, raise_on_error=True, level=0): + """If an email address is an alias, look it up and return the full name + + TODO: Why not just use git's own alias feature? + + Args: + lookup_name: Alias or email address to look up + alias: Dictionary containing aliases (None to use settings default) + raise_on_error: True to raise an error when an alias fails to match, + False to just print a message. + + Returns: + tuple: + list containing a list of email addresses + + Raises: + OSError if a recursive alias reference was found + ValueError if an alias was not found + + >>> alias = {} + >>> alias['fred'] = ['f.bloggs@napier.co.nz'] + >>> alias['john'] = ['j.bloggs@napier.co.nz'] + >>> alias['mary'] = ['m.poppins@cloud.net'] + >>> alias['boys'] = ['fred', ' john', 'f.bloggs@napier.co.nz'] + >>> alias['all'] = ['fred ', 'john', ' mary '] + >>> alias['loop'] = ['other', 'john', ' mary '] + >>> alias['other'] = ['loop', 'john', ' mary '] + >>> LookupEmail('mary', alias) + ['m.poppins@cloud.net'] + >>> LookupEmail('arthur.wellesley@howe.ro.uk', alias) + ['arthur.wellesley@howe.ro.uk'] + >>> LookupEmail('boys', alias) + ['f.bloggs@napier.co.nz', 'j.bloggs@napier.co.nz'] + >>> LookupEmail('all', alias) + ['f.bloggs@napier.co.nz', 'j.bloggs@napier.co.nz', 'm.poppins@cloud.net'] + >>> LookupEmail('odd', alias) + Traceback (most recent call last): + ... + ValueError: Alias 'odd' not found + >>> LookupEmail('loop', alias) + Traceback (most recent call last): + ... + OSError: Recursive email alias at 'other' + >>> LookupEmail('odd', alias, raise_on_error=False) + \033[1;31mAlias 'odd' not found\033[0m + [] + >>> # In this case the loop part will effectively be ignored. + >>> LookupEmail('loop', alias, raise_on_error=False) + \033[1;31mRecursive email alias at 'other'\033[0m + \033[1;31mRecursive email alias at 'john'\033[0m + \033[1;31mRecursive email alias at 'mary'\033[0m + ['j.bloggs@napier.co.nz', 'm.poppins@cloud.net'] + """ + if not alias: + alias = settings.alias + lookup_name = lookup_name.strip() + if '@' in lookup_name: # Perhaps a real email address + return [lookup_name] + + lookup_name = lookup_name.lower() + col = terminal.Color() + + out_list = [] + if level > 10: + msg = "Recursive email alias at '%s'" % lookup_name + if raise_on_error: + raise OSError, msg + else: + print col.Color(col.RED, msg) + return out_list + + if lookup_name: + if not lookup_name in alias: + msg = "Alias '%s' not found" % lookup_name + if raise_on_error: + raise ValueError, msg + else: + print col.Color(col.RED, msg) + return out_list + for item in alias[lookup_name]: + todo = LookupEmail(item, alias, raise_on_error, level + 1) + for new_item in todo: + if not new_item in out_list: + out_list.append(new_item) + + #print "No match for alias '%s'" % lookup_name + return out_list + +def GetTopLevel(): + """Return name of top-level directory for this git repo. + + Returns: + Full path to git top-level directory + + This test makes sure that we are running tests in the right subdir + + >>> os.path.realpath(os.path.dirname(__file__)) == \ + os.path.join(GetTopLevel(), 'tools', 'patman') + True + """ + return command.OutputOneLine('git', 'rev-parse', '--show-toplevel') + +def GetAliasFile(): + """Gets the name of the git alias file. + + Returns: + Filename of git alias file, or None if none + """ + fname = command.OutputOneLine('git', 'config', 'sendemail.aliasesfile', + raise_on_error=False) + if fname: + fname = os.path.join(GetTopLevel(), fname.strip()) + return fname + +def GetDefaultUserName(): + """Gets the user.name from .gitconfig file. + + Returns: + User name found in .gitconfig file, or None if none + """ + uname = command.OutputOneLine('git', 'config', '--global', 'user.name') + return uname + +def GetDefaultUserEmail(): + """Gets the user.email from the global .gitconfig file. + + Returns: + User's email found in .gitconfig file, or None if none + """ + uemail = command.OutputOneLine('git', 'config', '--global', 'user.email') + return uemail + +def Setup(): + """Set up git utils, by reading the alias files.""" + # Check for a git alias file also + alias_fname = GetAliasFile() + if alias_fname: + settings.ReadGitAliases(alias_fname) + +def GetHead(): + """Get the hash of the current HEAD + + Returns: + Hash of HEAD + """ + return command.OutputOneLine('git', 'show', '-s', '--pretty=format:%H') + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/qemu/roms/u-boot/tools/patman/patchstream.py b/qemu/roms/u-boot/tools/patman/patchstream.py new file mode 100644 index 000000000..9f5682cd0 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/patchstream.py @@ -0,0 +1,493 @@ +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import os +import re +import shutil +import tempfile + +import command +import commit +import gitutil +from series import Series + +# Tags that we detect and remove +re_remove = re.compile('^BUG=|^TEST=|^BRANCH=|^Change-Id:|^Review URL:' + '|Reviewed-on:|Commit-\w*:') + +# Lines which are allowed after a TEST= line +re_allowed_after_test = re.compile('^Signed-off-by:') + +# Signoffs +re_signoff = re.compile('^Signed-off-by: *(.*)') + +# The start of the cover letter +re_cover = re.compile('^Cover-letter:') + +# A cover letter Cc +re_cover_cc = re.compile('^Cover-letter-cc: *(.*)') + +# Patch series tag +re_series_tag = re.compile('^Series-([a-z-]*): *(.*)') + +# Commit series tag +re_commit_tag = re.compile('^Commit-([a-z-]*): *(.*)') + +# Commit tags that we want to collect and keep +re_tag = re.compile('^(Tested-by|Acked-by|Reviewed-by|Patch-cc): (.*)') + +# The start of a new commit in the git log +re_commit = re.compile('^commit ([0-9a-f]*)$') + +# We detect these since checkpatch doesn't always do it +re_space_before_tab = re.compile('^[+].* \t') + +# States we can be in - can we use range() and still have comments? +STATE_MSG_HEADER = 0 # Still in the message header +STATE_PATCH_SUBJECT = 1 # In patch subject (first line of log for a commit) +STATE_PATCH_HEADER = 2 # In patch header (after the subject) +STATE_DIFFS = 3 # In the diff part (past --- line) + +class PatchStream: + """Class for detecting/injecting tags in a patch or series of patches + + We support processing the output of 'git log' to read out the tags we + are interested in. We can also process a patch file in order to remove + unwanted tags or inject additional ones. These correspond to the two + phases of processing. + """ + def __init__(self, series, name=None, is_log=False): + self.skip_blank = False # True to skip a single blank line + self.found_test = False # Found a TEST= line + self.lines_after_test = 0 # MNumber of lines found after TEST= + self.warn = [] # List of warnings we have collected + self.linenum = 1 # Output line number we are up to + self.in_section = None # Name of start...END section we are in + self.notes = [] # Series notes + self.section = [] # The current section...END section + self.series = series # Info about the patch series + self.is_log = is_log # True if indent like git log + self.in_change = 0 # Non-zero if we are in a change list + self.blank_count = 0 # Number of blank lines stored up + self.state = STATE_MSG_HEADER # What state are we in? + self.tags = [] # Tags collected, like Tested-by... + self.signoff = [] # Contents of signoff line + self.commit = None # Current commit + + def AddToSeries(self, line, name, value): + """Add a new Series-xxx tag. + + When a Series-xxx tag is detected, we come here to record it, if we + are scanning a 'git log'. + + Args: + line: Source line containing tag (useful for debug/error messages) + name: Tag name (part after 'Series-') + value: Tag value (part after 'Series-xxx: ') + """ + if name == 'notes': + self.in_section = name + self.skip_blank = False + if self.is_log: + self.series.AddTag(self.commit, line, name, value) + + def AddToCommit(self, line, name, value): + """Add a new Commit-xxx tag. + + When a Commit-xxx tag is detected, we come here to record it. + + Args: + line: Source line containing tag (useful for debug/error messages) + name: Tag name (part after 'Commit-') + value: Tag value (part after 'Commit-xxx: ') + """ + if name == 'notes': + self.in_section = 'commit-' + name + self.skip_blank = False + + def CloseCommit(self): + """Save the current commit into our commit list, and reset our state""" + if self.commit and self.is_log: + self.series.AddCommit(self.commit) + self.commit = None + + def FormatTags(self, tags): + out_list = [] + for tag in sorted(tags): + if tag.startswith('Cc:'): + tag_list = tag[4:].split(',') + out_list += gitutil.BuildEmailList(tag_list, 'Cc:') + else: + out_list.append(tag) + return out_list + + def ProcessLine(self, line): + """Process a single line of a patch file or commit log + + This process a line and returns a list of lines to output. The list + may be empty or may contain multiple output lines. + + This is where all the complicated logic is located. The class's + state is used to move between different states and detect things + properly. + + We can be in one of two modes: + self.is_log == True: This is 'git log' mode, where most output is + indented by 4 characters and we are scanning for tags + + self.is_log == False: This is 'patch' mode, where we already have + all the tags, and are processing patches to remove junk we + don't want, and add things we think are required. + + Args: + line: text line to process + + Returns: + list of output lines, or [] if nothing should be output + """ + # Initially we have no output. Prepare the input line string + out = [] + line = line.rstrip('\n') + if self.is_log: + if line[:4] == ' ': + line = line[4:] + + # Handle state transition and skipping blank lines + series_tag_match = re_series_tag.match(line) + commit_tag_match = re_commit_tag.match(line) + commit_match = re_commit.match(line) if self.is_log else None + cover_cc_match = re_cover_cc.match(line) + signoff_match = re_signoff.match(line) + tag_match = None + if self.state == STATE_PATCH_HEADER: + tag_match = re_tag.match(line) + is_blank = not line.strip() + if is_blank: + if (self.state == STATE_MSG_HEADER + or self.state == STATE_PATCH_SUBJECT): + self.state += 1 + + # We don't have a subject in the text stream of patch files + # It has its own line with a Subject: tag + if not self.is_log and self.state == STATE_PATCH_SUBJECT: + self.state += 1 + elif commit_match: + self.state = STATE_MSG_HEADER + + # If we are in a section, keep collecting lines until we see END + if self.in_section: + if line == 'END': + if self.in_section == 'cover': + self.series.cover = self.section + elif self.in_section == 'notes': + if self.is_log: + self.series.notes += self.section + elif self.in_section == 'commit-notes': + if self.is_log: + self.commit.notes += self.section + else: + self.warn.append("Unknown section '%s'" % self.in_section) + self.in_section = None + self.skip_blank = True + self.section = [] + else: + self.section.append(line) + + # Detect the commit subject + elif not is_blank and self.state == STATE_PATCH_SUBJECT: + self.commit.subject = line + + # Detect the tags we want to remove, and skip blank lines + elif re_remove.match(line) and not commit_tag_match: + self.skip_blank = True + + # TEST= should be the last thing in the commit, so remove + # everything after it + if line.startswith('TEST='): + self.found_test = True + elif self.skip_blank and is_blank: + self.skip_blank = False + + # Detect the start of a cover letter section + elif re_cover.match(line): + self.in_section = 'cover' + self.skip_blank = False + + elif cover_cc_match: + value = cover_cc_match.group(1) + self.AddToSeries(line, 'cover-cc', value) + + # If we are in a change list, key collected lines until a blank one + elif self.in_change: + if is_blank: + # Blank line ends this change list + self.in_change = 0 + elif line == '---': + self.in_change = 0 + out = self.ProcessLine(line) + else: + if self.is_log: + self.series.AddChange(self.in_change, self.commit, line) + self.skip_blank = False + + # Detect Series-xxx tags + elif series_tag_match: + name = series_tag_match.group(1) + value = series_tag_match.group(2) + if name == 'changes': + # value is the version number: e.g. 1, or 2 + try: + value = int(value) + except ValueError as str: + raise ValueError("%s: Cannot decode version info '%s'" % + (self.commit.hash, line)) + self.in_change = int(value) + else: + self.AddToSeries(line, name, value) + self.skip_blank = True + + # Detect Commit-xxx tags + elif commit_tag_match: + name = commit_tag_match.group(1) + value = commit_tag_match.group(2) + if name == 'notes': + self.AddToCommit(line, name, value) + self.skip_blank = True + + # Detect the start of a new commit + elif commit_match: + self.CloseCommit() + # TODO: We should store the whole hash, and just display a subset + self.commit = commit.Commit(commit_match.group(1)[:8]) + + # Detect tags in the commit message + elif tag_match: + # Remove Tested-by self, since few will take much notice + if (tag_match.group(1) == 'Tested-by' and + tag_match.group(2).find(os.getenv('USER') + '@') != -1): + self.warn.append("Ignoring %s" % line) + elif tag_match.group(1) == 'Patch-cc': + self.commit.AddCc(tag_match.group(2).split(',')) + else: + self.tags.append(line); + + # Suppress duplicate signoffs + elif signoff_match: + if self.commit.CheckDuplicateSignoff(signoff_match.group(1)): + out = [line] + + # Well that means this is an ordinary line + else: + pos = 1 + # Look for ugly ASCII characters + for ch in line: + # TODO: Would be nicer to report source filename and line + if ord(ch) > 0x80: + self.warn.append("Line %d/%d ('%s') has funny ascii char" % + (self.linenum, pos, line)) + pos += 1 + + # Look for space before tab + m = re_space_before_tab.match(line) + if m: + self.warn.append('Line %d/%d has space before tab' % + (self.linenum, m.start())) + + # OK, we have a valid non-blank line + out = [line] + self.linenum += 1 + self.skip_blank = False + if self.state == STATE_DIFFS: + pass + + # If this is the start of the diffs section, emit our tags and + # change log + elif line == '---': + self.state = STATE_DIFFS + + # Output the tags (signeoff first), then change list + out = [] + log = self.series.MakeChangeLog(self.commit) + out += self.FormatTags(self.tags) + out += [line] + self.commit.notes + [''] + log + elif self.found_test: + if not re_allowed_after_test.match(line): + self.lines_after_test += 1 + + return out + + def Finalize(self): + """Close out processing of this patch stream""" + self.CloseCommit() + if self.lines_after_test: + self.warn.append('Found %d lines after TEST=' % + self.lines_after_test) + + def ProcessStream(self, infd, outfd): + """Copy a stream from infd to outfd, filtering out unwanting things. + + This is used to process patch files one at a time. + + Args: + infd: Input stream file object + outfd: Output stream file object + """ + # Extract the filename from each diff, for nice warnings + fname = None + last_fname = None + re_fname = re.compile('diff --git a/(.*) b/.*') + while True: + line = infd.readline() + if not line: + break + out = self.ProcessLine(line) + + # Try to detect blank lines at EOF + for line in out: + match = re_fname.match(line) + if match: + last_fname = fname + fname = match.group(1) + if line == '+': + self.blank_count += 1 + else: + if self.blank_count and (line == '-- ' or match): + self.warn.append("Found possible blank line(s) at " + "end of file '%s'" % last_fname) + outfd.write('+\n' * self.blank_count) + outfd.write(line + '\n') + self.blank_count = 0 + self.Finalize() + + +def GetMetaDataForList(commit_range, git_dir=None, count=None, + series = Series()): + """Reads out patch series metadata from the commits + + This does a 'git log' on the relevant commits and pulls out the tags we + are interested in. + + Args: + commit_range: Range of commits to count (e.g. 'HEAD..base') + git_dir: Path to git repositiory (None to use default) + count: Number of commits to list, or None for no limit + series: Series object to add information into. By default a new series + is started. + Returns: + A Series object containing information about the commits. + """ + params = ['git', 'log', '--no-color', '--reverse', '--no-decorate', + commit_range] + if count is not None: + params[2:2] = ['-n%d' % count] + if git_dir: + params[1:1] = ['--git-dir', git_dir] + pipe = [params] + stdout = command.RunPipe(pipe, capture=True).stdout + ps = PatchStream(series, is_log=True) + for line in stdout.splitlines(): + ps.ProcessLine(line) + ps.Finalize() + return series + +def GetMetaData(start, count): + """Reads out patch series metadata from the commits + + This does a 'git log' on the relevant commits and pulls out the tags we + are interested in. + + Args: + start: Commit to start from: 0=HEAD, 1=next one, etc. + count: Number of commits to list + """ + return GetMetaDataForList('HEAD~%d' % start, None, count) + +def FixPatch(backup_dir, fname, series, commit): + """Fix up a patch file, by adding/removing as required. + + We remove our tags from the patch file, insert changes lists, etc. + The patch file is processed in place, and overwritten. + + A backup file is put into backup_dir (if not None). + + Args: + fname: Filename to patch file to process + series: Series information about this patch set + commit: Commit object for this patch file + Return: + A list of errors, or [] if all ok. + """ + handle, tmpname = tempfile.mkstemp() + outfd = os.fdopen(handle, 'w') + infd = open(fname, 'r') + ps = PatchStream(series) + ps.commit = commit + ps.ProcessStream(infd, outfd) + infd.close() + outfd.close() + + # Create a backup file if required + if backup_dir: + shutil.copy(fname, os.path.join(backup_dir, os.path.basename(fname))) + shutil.move(tmpname, fname) + return ps.warn + +def FixPatches(series, fnames): + """Fix up a list of patches identified by filenames + + The patch files are processed in place, and overwritten. + + Args: + series: The series object + fnames: List of patch files to process + """ + # Current workflow creates patches, so we shouldn't need a backup + backup_dir = None #tempfile.mkdtemp('clean-patch') + count = 0 + for fname in fnames: + commit = series.commits[count] + commit.patch = fname + result = FixPatch(backup_dir, fname, series, commit) + if result: + print '%d warnings for %s:' % (len(result), fname) + for warn in result: + print '\t', warn + print + count += 1 + print 'Cleaned %d patches' % count + return series + +def InsertCoverLetter(fname, series, count): + """Inserts a cover letter with the required info into patch 0 + + Args: + fname: Input / output filename of the cover letter file + series: Series object + count: Number of patches in the series + """ + fd = open(fname, 'r') + lines = fd.readlines() + fd.close() + + fd = open(fname, 'w') + text = series.cover + prefix = series.GetPatchPrefix() + for line in lines: + if line.startswith('Subject:'): + # TODO: if more than 10 patches this should save 00/xx, not 0/xx + line = 'Subject: [%s 0/%d] %s\n' % (prefix, count, text[0]) + + # Insert our cover letter + elif line.startswith('*** BLURB HERE ***'): + # First the blurb test + line = '\n'.join(text[1:]) + '\n' + if series.get('notes'): + line += '\n'.join(series.notes) + '\n' + + # Now the change list + out = series.MakeChangeLog(None) + line += '\n' + '\n'.join(out) + fd.write(line) + fd.close() diff --git a/qemu/roms/u-boot/tools/patman/patman b/qemu/roms/u-boot/tools/patman/patman new file mode 120000 index 000000000..6cc3d7a56 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/patman @@ -0,0 +1 @@ +patman.py
\ No newline at end of file diff --git a/qemu/roms/u-boot/tools/patman/patman.py b/qemu/roms/u-boot/tools/patman/patman.py new file mode 100755 index 000000000..c60aa5a1c --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/patman.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +# +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +"""See README for more information""" + +from optparse import OptionParser +import os +import re +import sys +import unittest + +# Our modules +import checkpatch +import command +import gitutil +import patchstream +import project +import settings +import terminal +import test + + +parser = OptionParser() +parser.add_option('-a', '--no-apply', action='store_false', + dest='apply_patches', default=True, + help="Don't test-apply patches with git am") +parser.add_option('-H', '--full-help', action='store_true', dest='full_help', + default=False, help='Display the README file') +parser.add_option('-c', '--count', dest='count', type='int', + default=-1, help='Automatically create patches from top n commits') +parser.add_option('-i', '--ignore-errors', action='store_true', + dest='ignore_errors', default=False, + help='Send patches email even if patch errors are found') +parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run', + default=False, help="Do a dry run (create but don't email patches)") +parser.add_option('-p', '--project', default=project.DetectProject(), + help="Project name; affects default option values and " + "aliases [default: %default]") +parser.add_option('-r', '--in-reply-to', type='string', action='store', + help="Message ID that this series is in reply to") +parser.add_option('-s', '--start', dest='start', type='int', + default=0, help='Commit to start creating patches from (0 = HEAD)') +parser.add_option('-t', '--ignore-bad-tags', action='store_true', + default=False, help='Ignore bad tags / aliases') +parser.add_option('--test', action='store_true', dest='test', + default=False, help='run tests') +parser.add_option('-v', '--verbose', action='store_true', dest='verbose', + default=False, help='Verbose output of errors and warnings') +parser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store', + default=None, help='Output cc list for patch file (used by git)') +parser.add_option('--no-check', action='store_false', dest='check_patch', + default=True, + help="Don't check for patch compliance") +parser.add_option('--no-tags', action='store_false', dest='process_tags', + default=True, help="Don't process subject tags as aliaes") + +parser.usage = """patman [options] + +Create patches from commits in a branch, check them and email them as +specified by tags you place in the commits. Use -n to do a dry run first.""" + + +# Parse options twice: first to get the project and second to handle +# defaults properly (which depends on project). +(options, args) = parser.parse_args() +settings.Setup(parser, options.project, '') +(options, args) = parser.parse_args() + +# Run our meagre tests +if options.test: + import doctest + + sys.argv = [sys.argv[0]] + suite = unittest.TestLoader().loadTestsFromTestCase(test.TestPatch) + result = unittest.TestResult() + suite.run(result) + + for module in ['gitutil', 'settings']: + suite = doctest.DocTestSuite(module) + suite.run(result) + + # TODO: Surely we can just 'print' result? + print result + for test, err in result.errors: + print err + for test, err in result.failures: + print err + +# Called from git with a patch filename as argument +# Printout a list of additional CC recipients for this patch +elif options.cc_cmd: + fd = open(options.cc_cmd, 'r') + re_line = re.compile('(\S*) (.*)') + for line in fd.readlines(): + match = re_line.match(line) + if match and match.group(1) == args[0]: + for cc in match.group(2).split(', '): + cc = cc.strip() + if cc: + print cc + fd.close() + +elif options.full_help: + pager = os.getenv('PAGER') + if not pager: + pager = 'more' + fname = os.path.join(os.path.dirname(sys.argv[0]), 'README') + command.Run(pager, fname) + +# Process commits, produce patches files, check them, email them +else: + gitutil.Setup() + + if options.count == -1: + # Work out how many patches to send if we can + options.count = gitutil.CountCommitsToBranch() - options.start + + col = terminal.Color() + if not options.count: + str = 'No commits found to process - please use -c flag' + print col.Color(col.RED, str) + sys.exit(1) + + # Read the metadata from the commits + if options.count: + series = patchstream.GetMetaData(options.start, options.count) + cover_fname, args = gitutil.CreatePatches(options.start, options.count, + series) + + # Fix up the patch files to our liking, and insert the cover letter + series = patchstream.FixPatches(series, args) + if series and cover_fname and series.get('cover'): + patchstream.InsertCoverLetter(cover_fname, series, options.count) + + # Do a few checks on the series + series.DoChecks() + + # Check the patches, and run them through 'git am' just to be sure + if options.check_patch: + ok = checkpatch.CheckPatches(options.verbose, args) + else: + ok = True + if options.apply_patches: + if not gitutil.ApplyPatches(options.verbose, args, + options.count + options.start): + ok = False + + cc_file = series.MakeCcFile(options.process_tags, cover_fname, + not options.ignore_bad_tags) + + # Email the patches out (giving the user time to check / cancel) + cmd = '' + if ok or options.ignore_errors: + cmd = gitutil.EmailPatches(series, cover_fname, args, + options.dry_run, not options.ignore_bad_tags, cc_file, + in_reply_to=options.in_reply_to) + + # For a dry run, just show our actions as a sanity check + if options.dry_run: + series.ShowActions(args, cmd, options.process_tags) + + os.remove(cc_file) diff --git a/qemu/roms/u-boot/tools/patman/project.py b/qemu/roms/u-boot/tools/patman/project.py new file mode 100644 index 000000000..e05ff1163 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/project.py @@ -0,0 +1,27 @@ +# Copyright (c) 2012 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import os.path + +import gitutil + +def DetectProject(): + """Autodetect the name of the current project. + + This looks for signature files/directories that are unlikely to exist except + in the given project. + + Returns: + The name of the project, like "linux" or "u-boot". Returns "unknown" + if we can't detect the project. + """ + top_level = gitutil.GetTopLevel() + + if os.path.exists(os.path.join(top_level, "include", "u-boot")): + return "u-boot" + elif os.path.exists(os.path.join(top_level, "kernel")): + return "linux" + + return "unknown" diff --git a/qemu/roms/u-boot/tools/patman/series.py b/qemu/roms/u-boot/tools/patman/series.py new file mode 100644 index 000000000..88c0d877d --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/series.py @@ -0,0 +1,267 @@ +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import itertools +import os + +import get_maintainer +import gitutil +import terminal + +# Series-xxx tags that we understand +valid_series = ['to', 'cc', 'version', 'changes', 'prefix', 'notes', 'name', + 'cover-cc', 'process_log'] + +class Series(dict): + """Holds information about a patch series, including all tags. + + Vars: + cc: List of aliases/emails to Cc all patches to + commits: List of Commit objects, one for each patch + cover: List of lines in the cover letter + notes: List of lines in the notes + changes: (dict) List of changes for each version, The key is + the integer version number + allow_overwrite: Allow tags to overwrite an existing tag + """ + def __init__(self): + self.cc = [] + self.to = [] + self.cover_cc = [] + self.commits = [] + self.cover = None + self.notes = [] + self.changes = {} + self.allow_overwrite = False + + # Written in MakeCcFile() + # key: name of patch file + # value: list of email addresses + self._generated_cc = {} + + # These make us more like a dictionary + def __setattr__(self, name, value): + self[name] = value + + def __getattr__(self, name): + return self[name] + + def AddTag(self, commit, line, name, value): + """Add a new Series-xxx tag along with its value. + + Args: + line: Source line containing tag (useful for debug/error messages) + name: Tag name (part after 'Series-') + value: Tag value (part after 'Series-xxx: ') + """ + # If we already have it, then add to our list + name = name.replace('-', '_') + if name in self and not self.allow_overwrite: + values = value.split(',') + values = [str.strip() for str in values] + if type(self[name]) != type([]): + raise ValueError("In %s: line '%s': Cannot add another value " + "'%s' to series '%s'" % + (commit.hash, line, values, self[name])) + self[name] += values + + # Otherwise just set the value + elif name in valid_series: + self[name] = value + else: + raise ValueError("In %s: line '%s': Unknown 'Series-%s': valid " + "options are %s" % (commit.hash, line, name, + ', '.join(valid_series))) + + def AddCommit(self, commit): + """Add a commit into our list of commits + + We create a list of tags in the commit subject also. + + Args: + commit: Commit object to add + """ + commit.CheckTags() + self.commits.append(commit) + + def ShowActions(self, args, cmd, process_tags): + """Show what actions we will/would perform + + Args: + args: List of patch files we created + cmd: The git command we would have run + process_tags: Process tags as if they were aliases + """ + col = terminal.Color() + print 'Dry run, so not doing much. But I would do this:' + print + print 'Send a total of %d patch%s with %scover letter.' % ( + len(args), '' if len(args) == 1 else 'es', + self.get('cover') and 'a ' or 'no ') + + # TODO: Colour the patches according to whether they passed checks + for upto in range(len(args)): + commit = self.commits[upto] + print col.Color(col.GREEN, ' %s' % args[upto]) + cc_list = list(self._generated_cc[commit.patch]) + + # Skip items in To list + if 'to' in self: + try: + map(cc_list.remove, gitutil.BuildEmailList(self.to)) + except ValueError: + pass + + for email in cc_list: + if email == None: + email = col.Color(col.YELLOW, "<alias '%s' not found>" + % tag) + if email: + print ' Cc: ',email + print + for item in gitutil.BuildEmailList(self.get('to', '<none>')): + print 'To:\t ', item + for item in gitutil.BuildEmailList(self.cc): + print 'Cc:\t ', item + print 'Version: ', self.get('version') + print 'Prefix:\t ', self.get('prefix') + if self.cover: + print 'Cover: %d lines' % len(self.cover) + cover_cc = gitutil.BuildEmailList(self.get('cover_cc', '')) + all_ccs = itertools.chain(cover_cc, *self._generated_cc.values()) + for email in set(all_ccs): + print ' Cc: ',email + if cmd: + print 'Git command: %s' % cmd + + def MakeChangeLog(self, commit): + """Create a list of changes for each version. + + Return: + The change log as a list of strings, one per line + + Changes in v4: + - Jog the dial back closer to the widget + + Changes in v3: None + Changes in v2: + - Fix the widget + - Jog the dial + + etc. + """ + final = [] + process_it = self.get('process_log', '').split(',') + process_it = [item.strip() for item in process_it] + need_blank = False + for change in sorted(self.changes, reverse=True): + out = [] + for this_commit, text in self.changes[change]: + if commit and this_commit != commit: + continue + if 'uniq' not in process_it or text not in out: + out.append(text) + line = 'Changes in v%d:' % change + have_changes = len(out) > 0 + if 'sort' in process_it: + out = sorted(out) + if have_changes: + out.insert(0, line) + else: + out = [line + ' None'] + if need_blank: + out.insert(0, '') + final += out + need_blank = have_changes + if self.changes: + final.append('') + return final + + def DoChecks(self): + """Check that each version has a change log + + Print an error if something is wrong. + """ + col = terminal.Color() + if self.get('version'): + changes_copy = dict(self.changes) + for version in range(1, int(self.version) + 1): + if self.changes.get(version): + del changes_copy[version] + else: + if version > 1: + str = 'Change log missing for v%d' % version + print col.Color(col.RED, str) + for version in changes_copy: + str = 'Change log for unknown version v%d' % version + print col.Color(col.RED, str) + elif self.changes: + str = 'Change log exists, but no version is set' + print col.Color(col.RED, str) + + def MakeCcFile(self, process_tags, cover_fname, raise_on_error): + """Make a cc file for us to use for per-commit Cc automation + + Also stores in self._generated_cc to make ShowActions() faster. + + Args: + process_tags: Process tags as if they were aliases + cover_fname: If non-None the name of the cover letter. + raise_on_error: True to raise an error when an alias fails to match, + False to just print a message. + Return: + Filename of temp file created + """ + # Look for commit tags (of the form 'xxx:' at the start of the subject) + fname = '/tmp/patman.%d' % os.getpid() + fd = open(fname, 'w') + all_ccs = [] + for commit in self.commits: + list = [] + if process_tags: + list += gitutil.BuildEmailList(commit.tags, + raise_on_error=raise_on_error) + list += gitutil.BuildEmailList(commit.cc_list, + raise_on_error=raise_on_error) + list += get_maintainer.GetMaintainer(commit.patch) + all_ccs += list + print >>fd, commit.patch, ', '.join(list) + self._generated_cc[commit.patch] = list + + if cover_fname: + cover_cc = gitutil.BuildEmailList(self.get('cover_cc', '')) + print >>fd, cover_fname, ', '.join(set(cover_cc + all_ccs)) + + fd.close() + return fname + + def AddChange(self, version, commit, info): + """Add a new change line to a version. + + This will later appear in the change log. + + Args: + version: version number to add change list to + info: change line for this version + """ + if not self.changes.get(version): + self.changes[version] = [] + self.changes[version].append([commit, info]) + + def GetPatchPrefix(self): + """Get the patch version string + + Return: + Patch string, like 'RFC PATCH v5' or just 'PATCH' + """ + version = '' + if self.get('version'): + version = ' v%s' % self['version'] + + # Get patch name prefix + prefix = '' + if self.get('prefix'): + prefix = '%s ' % self['prefix'] + return '%sPATCH%s' % (prefix, version) diff --git a/qemu/roms/u-boot/tools/patman/settings.py b/qemu/roms/u-boot/tools/patman/settings.py new file mode 100644 index 000000000..122e8fd98 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/settings.py @@ -0,0 +1,268 @@ +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import ConfigParser +import os +import re + +import command +import gitutil + +"""Default settings per-project. + +These are used by _ProjectConfigParser. Settings names should match +the "dest" of the option parser from patman.py. +""" +_default_settings = { + "u-boot": {}, + "linux": { + "process_tags": "False", + } +} + +class _ProjectConfigParser(ConfigParser.SafeConfigParser): + """ConfigParser that handles projects. + + There are two main goals of this class: + - Load project-specific default settings. + - Merge general default settings/aliases with project-specific ones. + + # Sample config used for tests below... + >>> import StringIO + >>> sample_config = ''' + ... [alias] + ... me: Peter P. <likesspiders@example.com> + ... enemies: Evil <evil@example.com> + ... + ... [sm_alias] + ... enemies: Green G. <ugly@example.com> + ... + ... [sm2_alias] + ... enemies: Doc O. <pus@example.com> + ... + ... [settings] + ... am_hero: True + ... ''' + + # Check to make sure that bogus project gets general alias. + >>> config = _ProjectConfigParser("zzz") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> config.get("alias", "enemies") + 'Evil <evil@example.com>' + + # Check to make sure that alias gets overridden by project. + >>> config = _ProjectConfigParser("sm") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> config.get("alias", "enemies") + 'Green G. <ugly@example.com>' + + # Check to make sure that settings get merged with project. + >>> config = _ProjectConfigParser("linux") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> sorted(config.items("settings")) + [('am_hero', 'True'), ('process_tags', 'False')] + + # Check to make sure that settings works with unknown project. + >>> config = _ProjectConfigParser("unknown") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> sorted(config.items("settings")) + [('am_hero', 'True')] + """ + def __init__(self, project_name): + """Construct _ProjectConfigParser. + + In addition to standard SafeConfigParser initialization, this also loads + project defaults. + + Args: + project_name: The name of the project. + """ + self._project_name = project_name + ConfigParser.SafeConfigParser.__init__(self) + + # Update the project settings in the config based on + # the _default_settings global. + project_settings = "%s_settings" % project_name + if not self.has_section(project_settings): + self.add_section(project_settings) + project_defaults = _default_settings.get(project_name, {}) + for setting_name, setting_value in project_defaults.iteritems(): + self.set(project_settings, setting_name, setting_value) + + def get(self, section, option, *args, **kwargs): + """Extend SafeConfigParser to try project_section before section. + + Args: + See SafeConfigParser. + Returns: + See SafeConfigParser. + """ + try: + return ConfigParser.SafeConfigParser.get( + self, "%s_%s" % (self._project_name, section), option, + *args, **kwargs + ) + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): + return ConfigParser.SafeConfigParser.get( + self, section, option, *args, **kwargs + ) + + def items(self, section, *args, **kwargs): + """Extend SafeConfigParser to add project_section to section. + + Args: + See SafeConfigParser. + Returns: + See SafeConfigParser. + """ + project_items = [] + has_project_section = False + top_items = [] + + # Get items from the project section + try: + project_items = ConfigParser.SafeConfigParser.items( + self, "%s_%s" % (self._project_name, section), *args, **kwargs + ) + has_project_section = True + except ConfigParser.NoSectionError: + pass + + # Get top-level items + try: + top_items = ConfigParser.SafeConfigParser.items( + self, section, *args, **kwargs + ) + except ConfigParser.NoSectionError: + # If neither section exists raise the error on... + if not has_project_section: + raise + + item_dict = dict(top_items) + item_dict.update(project_items) + return item_dict.items() + +def ReadGitAliases(fname): + """Read a git alias file. This is in the form used by git: + + alias uboot u-boot@lists.denx.de + alias wd Wolfgang Denk <wd@denx.de> + + Args: + fname: Filename to read + """ + try: + fd = open(fname, 'r') + except IOError: + print "Warning: Cannot find alias file '%s'" % fname + return + + re_line = re.compile('alias\s+(\S+)\s+(.*)') + for line in fd.readlines(): + line = line.strip() + if not line or line[0] == '#': + continue + + m = re_line.match(line) + if not m: + print "Warning: Alias file line '%s' not understood" % line + continue + + list = alias.get(m.group(1), []) + for item in m.group(2).split(','): + item = item.strip() + if item: + list.append(item) + alias[m.group(1)] = list + + fd.close() + +def CreatePatmanConfigFile(config_fname): + """Creates a config file under $(HOME)/.patman if it can't find one. + + Args: + config_fname: Default config filename i.e., $(HOME)/.patman + + Returns: + None + """ + name = gitutil.GetDefaultUserName() + if name == None: + name = raw_input("Enter name: ") + + email = gitutil.GetDefaultUserEmail() + + if email == None: + email = raw_input("Enter email: ") + + try: + f = open(config_fname, 'w') + except IOError: + print "Couldn't create patman config file\n" + raise + + print >>f, "[alias]\nme: %s <%s>" % (name, email) + f.close(); + +def _UpdateDefaults(parser, config): + """Update the given OptionParser defaults based on config. + + We'll walk through all of the settings from the parser + For each setting we'll look for a default in the option parser. + If it's found we'll update the option parser default. + + The idea here is that the .patman file should be able to update + defaults but that command line flags should still have the final + say. + + Args: + parser: An instance of an OptionParser whose defaults will be + updated. + config: An instance of _ProjectConfigParser that we will query + for settings. + """ + defaults = parser.get_default_values() + for name, val in config.items('settings'): + if hasattr(defaults, name): + default_val = getattr(defaults, name) + if isinstance(default_val, bool): + val = config.getboolean('settings', name) + elif isinstance(default_val, int): + val = config.getint('settings', name) + parser.set_default(name, val) + else: + print "WARNING: Unknown setting %s" % name + +def Setup(parser, project_name, config_fname=''): + """Set up the settings module by reading config files. + + Args: + parser: The parser to update + project_name: Name of project that we're working on; we'll look + for sections named "project_section" as well. + config_fname: Config filename to read ('' for default) + """ + config = _ProjectConfigParser(project_name) + if config_fname == '': + config_fname = '%s/.patman' % os.getenv('HOME') + + if not os.path.exists(config_fname): + print "No config file found ~/.patman\nCreating one...\n" + CreatePatmanConfigFile(config_fname) + + config.read(config_fname) + + for name, value in config.items('alias'): + alias[name] = value.split(',') + + _UpdateDefaults(parser, config) + +# These are the aliases we understand, indexed by alias. Each member is a list. +alias = {} + +if __name__ == "__main__": + import doctest + + doctest.testmod() diff --git a/qemu/roms/u-boot/tools/patman/terminal.py b/qemu/roms/u-boot/tools/patman/terminal.py new file mode 100644 index 000000000..597d52686 --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/terminal.py @@ -0,0 +1,80 @@ +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +"""Terminal utilities + +This module handles terminal interaction including ANSI color codes. +""" + +import os +import sys + +# Selection of when we want our output to be colored +COLOR_IF_TERMINAL, COLOR_ALWAYS, COLOR_NEVER = range(3) + +class Color(object): + """Conditionally wraps text in ANSI color escape sequences.""" + BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8) + BOLD = -1 + BRIGHT_START = '\033[1;%dm' + NORMAL_START = '\033[22;%dm' + BOLD_START = '\033[1m' + RESET = '\033[0m' + + def __init__(self, colored=COLOR_IF_TERMINAL): + """Create a new Color object, optionally disabling color output. + + Args: + enabled: True if color output should be enabled. If False then this + class will not add color codes at all. + """ + self._enabled = (colored == COLOR_ALWAYS or + (colored == COLOR_IF_TERMINAL and os.isatty(sys.stdout.fileno()))) + + def Start(self, color, bright=True): + """Returns a start color code. + + Args: + color: Color to use, .e.g BLACK, RED, etc. + + Returns: + If color is enabled, returns an ANSI sequence to start the given color, + otherwise returns empty string + """ + if self._enabled: + base = self.BRIGHT_START if bright else self.NORMAL_START + return base % (color + 30) + return '' + + def Stop(self): + """Retruns a stop color code. + + Returns: + If color is enabled, returns an ANSI color reset sequence, otherwise + returns empty string + """ + if self._enabled: + return self.RESET + return '' + + def Color(self, color, text, bright=True): + """Returns text with conditionally added color escape sequences. + + Keyword arguments: + color: Text color -- one of the color constants defined in this class. + text: The text to color. + + Returns: + If self._enabled is False, returns the original text. If it's True, + returns text with color escape sequences based on the value of color. + """ + if not self._enabled: + return text + if color == self.BOLD: + start = self.BOLD_START + else: + base = self.BRIGHT_START if bright else self.NORMAL_START + start = base % (color + 30) + return start + text + self.RESET diff --git a/qemu/roms/u-boot/tools/patman/test.py b/qemu/roms/u-boot/tools/patman/test.py new file mode 100644 index 000000000..8fcfe530d --- /dev/null +++ b/qemu/roms/u-boot/tools/patman/test.py @@ -0,0 +1,242 @@ +# +# Copyright (c) 2011 The Chromium OS Authors. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +import os +import tempfile +import unittest + +import checkpatch +import gitutil +import patchstream +import series + + +class TestPatch(unittest.TestCase): + """Test this program + + TODO: Write tests for the rest of the functionality + """ + + def testBasic(self): + """Test basic filter operation""" + data=''' + +From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001 +From: Simon Glass <sjg@chromium.org> +Date: Thu, 28 Apr 2011 09:58:51 -0700 +Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support + +This adds functions to enable/disable clocks and reset to on-chip peripherals. + +BUG=chromium-os:13875 +TEST=build U-Boot for Seaboard, boot + +Change-Id: I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413 + +Review URL: http://codereview.chromium.org/6900006 + +Signed-off-by: Simon Glass <sjg@chromium.org> +--- + arch/arm/cpu/armv7/tegra2/Makefile | 2 +- + arch/arm/cpu/armv7/tegra2/ap20.c | 57 ++---- + arch/arm/cpu/armv7/tegra2/clock.c | 163 +++++++++++++++++ +''' + expected=''' + +From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001 +From: Simon Glass <sjg@chromium.org> +Date: Thu, 28 Apr 2011 09:58:51 -0700 +Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support + +This adds functions to enable/disable clocks and reset to on-chip peripherals. + +Signed-off-by: Simon Glass <sjg@chromium.org> +--- + arch/arm/cpu/armv7/tegra2/Makefile | 2 +- + arch/arm/cpu/armv7/tegra2/ap20.c | 57 ++---- + arch/arm/cpu/armv7/tegra2/clock.c | 163 +++++++++++++++++ +''' + out = '' + inhandle, inname = tempfile.mkstemp() + infd = os.fdopen(inhandle, 'w') + infd.write(data) + infd.close() + + exphandle, expname = tempfile.mkstemp() + expfd = os.fdopen(exphandle, 'w') + expfd.write(expected) + expfd.close() + + patchstream.FixPatch(None, inname, series.Series(), None) + rc = os.system('diff -u %s %s' % (inname, expname)) + self.assertEqual(rc, 0) + + os.remove(inname) + os.remove(expname) + + def GetData(self, data_type): + data=''' +From 4924887af52713cabea78420eff03badea8f0035 Mon Sep 17 00:00:00 2001 +From: Simon Glass <sjg@chromium.org> +Date: Thu, 7 Apr 2011 10:14:41 -0700 +Subject: [PATCH 1/4] Add microsecond boot time measurement + +This defines the basics of a new boot time measurement feature. This allows +logging of very accurate time measurements as the boot proceeds, by using +an available microsecond counter. + +%s +--- + README | 11 ++++++++ + common/bootstage.c | 50 ++++++++++++++++++++++++++++++++++++ + include/bootstage.h | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++ + include/common.h | 8 ++++++ + 5 files changed, 141 insertions(+), 0 deletions(-) + create mode 100644 common/bootstage.c + create mode 100644 include/bootstage.h + +diff --git a/README b/README +index 6f3748d..f9e4e65 100644 +--- a/README ++++ b/README +@@ -2026,6 +2026,17 @@ The following options need to be configured: + example, some LED's) on your board. At the moment, + the following checkpoints are implemented: + ++- Time boot progress ++ CONFIG_BOOTSTAGE ++ ++ Define this option to enable microsecond boot stage timing ++ on supported platforms. For this to work your platform ++ needs to define a function timer_get_us() which returns the ++ number of microseconds since reset. This would normally ++ be done in your SOC or board timer.c file. ++ ++ You can add calls to bootstage_mark() to set time markers. ++ + - Standalone program support: + CONFIG_STANDALONE_LOAD_ADDR + +diff --git a/common/bootstage.c b/common/bootstage.c +new file mode 100644 +index 0000000..2234c87 +--- /dev/null ++++ b/common/bootstage.c +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (c) 2011, Google Inc. All rights reserved. ++ * ++ * SPDX-License-Identifier: GPL-2.0+ ++ */ ++ ++ ++/* ++ * This module records the progress of boot and arbitrary commands, and ++ * permits accurate timestamping of each. The records can optionally be ++ * passed to kernel in the ATAGs ++ */ ++ ++#include <common.h> ++ ++ ++struct bootstage_record { ++ uint32_t time_us; ++ const char *name; ++}; ++ ++static struct bootstage_record record[BOOTSTAGE_COUNT]; ++ ++uint32_t bootstage_mark(enum bootstage_id id, const char *name) ++{ ++ struct bootstage_record *rec = &record[id]; ++ ++ /* Only record the first event for each */ ++%sif (!rec->name) { ++ rec->time_us = (uint32_t)timer_get_us(); ++ rec->name = name; ++ } ++ if (!rec->name && ++ %ssomething_else) { ++ rec->time_us = (uint32_t)timer_get_us(); ++ rec->name = name; ++ } ++%sreturn rec->time_us; ++} +-- +1.7.3.1 +''' + signoff = 'Signed-off-by: Simon Glass <sjg@chromium.org>\n' + tab = ' ' + indent = ' ' + if data_type == 'good': + pass + elif data_type == 'no-signoff': + signoff = '' + elif data_type == 'spaces': + tab = ' ' + elif data_type == 'indent': + indent = tab + else: + print 'not implemented' + return data % (signoff, tab, indent, tab) + + def SetupData(self, data_type): + inhandle, inname = tempfile.mkstemp() + infd = os.fdopen(inhandle, 'w') + data = self.GetData(data_type) + infd.write(data) + infd.close() + return inname + + def testGood(self): + """Test checkpatch operation""" + inf = self.SetupData('good') + result = checkpatch.CheckPatch(inf) + self.assertEqual(result.ok, True) + self.assertEqual(result.problems, []) + self.assertEqual(result.errors, 0) + self.assertEqual(result.warnings, 0) + self.assertEqual(result.checks, 0) + self.assertEqual(result.lines, 67) + os.remove(inf) + + def testNoSignoff(self): + inf = self.SetupData('no-signoff') + result = checkpatch.CheckPatch(inf) + self.assertEqual(result.ok, False) + self.assertEqual(len(result.problems), 1) + self.assertEqual(result.errors, 1) + self.assertEqual(result.warnings, 0) + self.assertEqual(result.checks, 0) + self.assertEqual(result.lines, 67) + os.remove(inf) + + def testSpaces(self): + inf = self.SetupData('spaces') + result = checkpatch.CheckPatch(inf) + self.assertEqual(result.ok, False) + self.assertEqual(len(result.problems), 1) + self.assertEqual(result.errors, 0) + self.assertEqual(result.warnings, 1) + self.assertEqual(result.checks, 0) + self.assertEqual(result.lines, 67) + os.remove(inf) + + def testIndent(self): + inf = self.SetupData('indent') + result = checkpatch.CheckPatch(inf) + self.assertEqual(result.ok, False) + self.assertEqual(len(result.problems), 1) + self.assertEqual(result.errors, 0) + self.assertEqual(result.warnings, 0) + self.assertEqual(result.checks, 1) + self.assertEqual(result.lines, 67) + os.remove(inf) + + +if __name__ == "__main__": + unittest.main() + gitutil.RunTests() diff --git a/qemu/roms/u-boot/tools/pblimage.c b/qemu/roms/u-boot/tools/pblimage.c new file mode 100644 index 000000000..ef3d7f629 --- /dev/null +++ b/qemu/roms/u-boot/tools/pblimage.c @@ -0,0 +1,331 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include "imagetool.h" +#include <image.h> +#include "pblimage.h" + +/* + * Initialize to an invalid value. + */ +static uint32_t next_pbl_cmd = 0x82000000; +/* + * need to store all bytes in memory for calculating crc32, then write the + * bytes to image file for PBL boot. + */ +static unsigned char mem_buf[1000000]; +static unsigned char *pmem_buf = mem_buf; +static int pbl_size; +static char *fname = "Unknown"; +static int lineno = -1; +static struct pbl_header pblimage_header; + +static union +{ + char c[4]; + unsigned char l; +} endian_test = { {'l', '?', '?', 'b'} }; + +#define ENDIANNESS ((char)endian_test.l) + +/* + * The PBL can load up to 64 bytes at a time, so we split the U-Boot + * image into 64 byte chunks. PBL needs a command for each piece, of + * the form "81xxxxxx", where "xxxxxx" is the offset. Calculate the + * start offset by subtracting the size of the u-boot image from the + * top of the allowable 24-bit range. + */ +static void init_next_pbl_cmd(FILE *fp_uboot) +{ + struct stat st; + int fd = fileno(fp_uboot); + + if (fstat(fd, &st) == -1) { + printf("Error: Could not determine u-boot image size. %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + } + + next_pbl_cmd = 0x82000000 - st.st_size; +} + +static void generate_pbl_cmd(void) +{ + uint32_t val = next_pbl_cmd; + next_pbl_cmd += 0x40; + int i; + + for (i = 3; i >= 0; i--) { + *pmem_buf++ = (val >> (i * 8)) & 0xff; + pbl_size++; + } +} + +static void pbl_fget(size_t size, FILE *stream) +{ + unsigned char c; + int c_temp; + + while (size && (c_temp = fgetc(stream)) != EOF) { + c = (unsigned char)c_temp; + *pmem_buf++ = c; + pbl_size++; + size--; + } +} + +/* load split u-boot with PBI command 81xxxxxx. */ +static void load_uboot(FILE *fp_uboot) +{ + init_next_pbl_cmd(fp_uboot); + while (next_pbl_cmd < 0x82000000) { + generate_pbl_cmd(); + pbl_fget(64, fp_uboot); + } +} + +static void check_get_hexval(char *token) +{ + uint32_t hexval; + int i; + + if (!sscanf(token, "%x", &hexval)) { + printf("Error:%s[%d] - Invalid hex data(%s)\n", fname, + lineno, token); + exit(EXIT_FAILURE); + } + for (i = 3; i >= 0; i--) { + *pmem_buf++ = (hexval >> (i * 8)) & 0xff; + pbl_size++; + } +} + +static void pbl_parser(char *name) +{ + FILE *fd = NULL; + char *line = NULL; + char *token, *saveptr1, *saveptr2; + size_t len = 0; + + fname = name; + fd = fopen(name, "r"); + if (fd == NULL) { + printf("Error:%s - Can't open\n", fname); + exit(EXIT_FAILURE); + } + + while ((getline(&line, &len, fd)) > 0) { + lineno++; + token = strtok_r(line, "\r\n", &saveptr1); + /* drop all lines with zero tokens (= empty lines) */ + if (token == NULL) + continue; + for (line = token;; line = NULL) { + token = strtok_r(line, " \t", &saveptr2); + if (token == NULL) + break; + /* Drop all text starting with '#' as comments */ + if (token[0] == '#') + break; + check_get_hexval(token); + } + } + if (line) + free(line); + fclose(fd); +} + +static uint32_t crc_table[256]; + +static void make_crc_table(void) +{ + uint32_t mask; + int i, j; + uint32_t poly; /* polynomial exclusive-or pattern */ + + /* + * the polynomial used by PBL is 1 + x1 + x2 + x4 + x5 + x7 + x8 + x10 + * + x11 + x12 + x16 + x22 + x23 + x26 + x32. + */ + poly = 0x04c11db7; + + for (i = 0; i < 256; i++) { + mask = i << 24; + for (j = 0; j < 8; j++) { + if (mask & 0x80000000) + mask = (mask << 1) ^ poly; + else + mask <<= 1; + } + crc_table[i] = mask; + } +} + +unsigned long pbl_crc32(unsigned long crc, const char *buf, uint32_t len) +{ + uint32_t crc32_val = 0xffffffff; + uint32_t xor = 0x0; + int i; + + make_crc_table(); + + for (i = 0; i < len; i++) + crc32_val = (crc32_val << 8) ^ + crc_table[(crc32_val >> 24) ^ (*buf++ & 0xff)]; + + crc32_val = crc32_val ^ xor; + if (crc32_val < 0) { + crc32_val += 0xffffffff; + crc32_val += 1; + } + return crc32_val; +} + +static uint32_t reverse_byte(uint32_t val) +{ + uint32_t temp; + unsigned char *p1; + int j; + + temp = val; + p1 = (unsigned char *)&temp; + for (j = 3; j >= 0; j--) + *p1++ = (val >> (j * 8)) & 0xff; + return temp; +} + +/* write end command and crc command to memory. */ +static void add_end_cmd(void) +{ + uint32_t pbl_end_cmd[4] = {0x09138000, 0x00000000, + 0x091380c0, 0x00000000}; + uint32_t crc32_pbl; + int i; + unsigned char *p = (unsigned char *)&pbl_end_cmd; + + if (ENDIANNESS == 'l') { + for (i = 0; i < 4; i++) + pbl_end_cmd[i] = reverse_byte(pbl_end_cmd[i]); + } + + for (i = 0; i < 16; i++) { + *pmem_buf++ = *p++; + pbl_size++; + } + + /* Add PBI CRC command. */ + *pmem_buf++ = 0x08; + *pmem_buf++ = 0x13; + *pmem_buf++ = 0x80; + *pmem_buf++ = 0x40; + pbl_size += 4; + + /* calculated CRC32 and write it to memory. */ + crc32_pbl = pbl_crc32(0, (const char *)mem_buf, pbl_size); + *pmem_buf++ = (crc32_pbl >> 24) & 0xff; + *pmem_buf++ = (crc32_pbl >> 16) & 0xff; + *pmem_buf++ = (crc32_pbl >> 8) & 0xff; + *pmem_buf++ = (crc32_pbl) & 0xff; + pbl_size += 4; + + if ((pbl_size % 16) != 0) { + for (i = 0; i < 8; i++) { + *pmem_buf++ = 0x0; + pbl_size++; + } + } + if ((pbl_size % 16 != 0)) { + printf("Error: Bad size of image file\n"); + exit(EXIT_FAILURE); + } +} + +void pbl_load_uboot(int ifd, struct image_tool_params *params) +{ + FILE *fp_uboot; + int size; + + /* parse the rcw.cfg file. */ + pbl_parser(params->imagename); + + /* parse the pbi.cfg file. */ + pbl_parser(params->imagename2); + + fp_uboot = fopen(params->datafile, "r"); + if (fp_uboot == NULL) { + printf("Error: %s open failed\n", params->datafile); + exit(EXIT_FAILURE); + } + + load_uboot(fp_uboot); + add_end_cmd(); + fclose(fp_uboot); + lseek(ifd, 0, SEEK_SET); + + size = pbl_size; + if (write(ifd, (const void *)&mem_buf, size) != size) { + fprintf(stderr, "Write error on %s: %s\n", + params->imagefile, strerror(errno)); + exit(EXIT_FAILURE); + } +} + +static int pblimage_check_image_types(uint8_t type) +{ + if (type == IH_TYPE_PBLIMAGE) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +} + +static int pblimage_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + struct pbl_header *pbl_hdr = (struct pbl_header *) ptr; + + /* Only a few checks can be done: search for magic numbers */ + if (ENDIANNESS == 'l') { + if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE)) + return -FDT_ERR_BADSTRUCTURE; + + if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER)) + return -FDT_ERR_BADSTRUCTURE; + } else { + if (pbl_hdr->preamble != RCW_PREAMBLE) + return -FDT_ERR_BADSTRUCTURE; + + if (pbl_hdr->rcwheader != RCW_HEADER) + return -FDT_ERR_BADSTRUCTURE; + } + return 0; +} + +static void pblimage_print_header(const void *ptr) +{ + printf("Image Type: Freescale PBL Boot Image\n"); +} + +static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + /*nothing need to do, pbl_load_uboot takes care of whole file. */ +} + +/* pblimage parameters */ +static struct image_type_params pblimage_params = { + .name = "Freescale PBL Boot Image support", + .header_size = sizeof(struct pbl_header), + .hdr = (void *)&pblimage_header, + .check_image_type = pblimage_check_image_types, + .verify_header = pblimage_verify_header, + .print_header = pblimage_print_header, + .set_header = pblimage_set_header, +}; + +void init_pbl_image_type(void) +{ + pbl_size = 0; + register_image_type(&pblimage_params); +} diff --git a/qemu/roms/u-boot/tools/pblimage.h b/qemu/roms/u-boot/tools/pblimage.h new file mode 100644 index 000000000..12bece50a --- /dev/null +++ b/qemu/roms/u-boot/tools/pblimage.h @@ -0,0 +1,20 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef PBLIMAGE_H +#define PBLIMAGE_H + +#define RCW_BYTES 64 +#define RCW_PREAMBLE 0xaa55aa55 +#define RCW_HEADER 0x010e0100 + +struct pbl_header { + uint32_t preamble; + uint32_t rcwheader; + uint8_t rcw_data[RCW_BYTES]; +}; + +#endif /* PBLIMAGE_H */ diff --git a/qemu/roms/u-boot/tools/proftool.c b/qemu/roms/u-boot/tools/proftool.c new file mode 100644 index 000000000..348295198 --- /dev/null +++ b/qemu/roms/u-boot/tools/proftool.c @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Decode and dump U-Boot profiling information */ + +#include <assert.h> +#include <ctype.h> +#include <limits.h> +#include <regex.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/param.h> + +#include <compiler.h> +#include <trace.h> + +#define MAX_LINE_LEN 500 + +enum { + FUNCF_TRACE = 1 << 0, /* Include this function in trace */ +}; + +struct func_info { + unsigned long offset; + const char *name; + unsigned long code_size; + unsigned long call_count; + unsigned flags; + /* the section this function is in */ + struct objsection_info *objsection; +}; + +enum trace_line_type { + TRACE_LINE_INCLUDE, + TRACE_LINE_EXCLUDE, +}; + +struct trace_configline_info { + struct trace_configline_info *next; + enum trace_line_type type; + const char *name; /* identifier name / wildcard */ + regex_t regex; /* Regex to use if name starts with / */ +}; + +/* The contents of the trace config file */ +struct trace_configline_info *trace_config_head; + +struct func_info *func_list; +int func_count; +struct trace_call *call_list; +int call_count; +int verbose; /* Verbosity level 0=none, 1=warn, 2=notice, 3=info, 4=debug */ +unsigned long text_offset; /* text address of first function */ + +static void outf(int level, const char *fmt, ...) + __attribute__ ((format (__printf__, 2, 3))); +#define error(fmt, b...) outf(0, fmt, ##b) +#define warn(fmt, b...) outf(1, fmt, ##b) +#define notice(fmt, b...) outf(2, fmt, ##b) +#define info(fmt, b...) outf(3, fmt, ##b) +#define debug(fmt, b...) outf(4, fmt, ##b) + + +static void outf(int level, const char *fmt, ...) +{ + if (verbose >= level) { + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + } +} + +static void usage(void) +{ + fprintf(stderr, + "Usage: proftool -cds -v3 <cmd> <profdata>\n" + "\n" + "Commands\n" + " dump-ftrace\t\tDump out textual data in ftrace format\n" + "\n" + "Options:\n" + " -m <map>\tSpecify Systen.map file\n" + " -t <trace>\tSpecific trace data file (from U-Boot)\n" + " -v <0-4>\tSpecify verbosity\n"); + exit(EXIT_FAILURE); +} + +static int h_cmp_offset(const void *v1, const void *v2) +{ + const struct func_info *f1 = v1, *f2 = v2; + + return (f1->offset / FUNC_SITE_SIZE) - (f2->offset / FUNC_SITE_SIZE); +} + +static int read_system_map(FILE *fin) +{ + unsigned long offset, start = 0; + struct func_info *func; + char buff[MAX_LINE_LEN]; + char symtype; + char symname[MAX_LINE_LEN + 1]; + int linenum; + int alloced; + + for (linenum = 1, alloced = func_count = 0;; linenum++) { + int fields = 0; + + if (fgets(buff, sizeof(buff), fin)) + fields = sscanf(buff, "%lx %c %100s\n", &offset, + &symtype, symname); + if (fields == 2) { + continue; + } else if (feof(fin)) { + break; + } else if (fields < 2) { + error("Map file line %d: invalid format\n", linenum); + return 1; + } + + /* Must be a text symbol */ + symtype = tolower(symtype); + if (symtype != 't' && symtype != 'w') + continue; + + if (func_count == alloced) { + alloced += 256; + func_list = realloc(func_list, + sizeof(struct func_info) * alloced); + assert(func_list); + } + if (!func_count) + start = offset; + + func = &func_list[func_count++]; + memset(func, '\0', sizeof(*func)); + func->offset = offset - start; + func->name = strdup(symname); + func->flags = FUNCF_TRACE; /* trace by default */ + + /* Update previous function's code size */ + if (func_count > 1) + func[-1].code_size = func->offset - func[-1].offset; + } + notice("%d functions found in map file\n", func_count); + text_offset = start; + return 0; +} + +static int read_data(FILE *fin, void *buff, int size) +{ + int err; + + err = fread(buff, 1, size, fin); + if (!err) + return 1; + if (err != size) { + error("Cannot read profile file at pos %ld\n", ftell(fin)); + return -1; + } + return 0; +} + +static struct func_info *find_func_by_offset(uint32_t offset) +{ + struct func_info key, *found; + + key.offset = offset; + found = bsearch(&key, func_list, func_count, sizeof(struct func_info), + h_cmp_offset); + + return found; +} + +/* This finds the function which contains the given offset */ +static struct func_info *find_caller_by_offset(uint32_t offset) +{ + int low; /* least function that could be a match */ + int high; /* greated function that could be a match */ + struct func_info key; + + low = 0; + high = func_count - 1; + key.offset = offset; + while (high > low + 1) { + int mid = (low + high) / 2; + int result; + + result = h_cmp_offset(&key, &func_list[mid]); + if (result > 0) + low = mid; + else if (result < 0) + high = mid; + else + return &func_list[mid]; + } + + return low >= 0 ? &func_list[low] : NULL; +} + +static int read_calls(FILE *fin, int count) +{ + struct trace_call *call_data; + int i; + + notice("call count: %d\n", count); + call_list = (struct trace_call *)calloc(count, sizeof(*call_data)); + if (!call_list) { + error("Cannot allocate call_list\n"); + return -1; + } + call_count = count; + + call_data = call_list; + for (i = 0; i < count; i++, call_data++) { + if (read_data(fin, call_data, sizeof(*call_data))) + return 1; + } + return 0; +} + +static int read_profile(FILE *fin, int *not_found) +{ + struct trace_output_hdr hdr; + + *not_found = 0; + while (!feof(fin)) { + int err; + + err = read_data(fin, &hdr, sizeof(hdr)); + if (err == 1) + break; /* EOF */ + else if (err) + return 1; + + switch (hdr.type) { + case TRACE_CHUNK_FUNCS: + /* Ignored at present */ + break; + + case TRACE_CHUNK_CALLS: + if (read_calls(fin, hdr.rec_count)) + return 1; + break; + } + } + return 0; +} + +static int read_map_file(const char *fname) +{ + FILE *fmap; + int err = 0; + + fmap = fopen(fname, "r"); + if (!fmap) { + error("Cannot open map file '%s'\n", fname); + return 1; + } + if (fmap) { + err = read_system_map(fmap); + fclose(fmap); + } + return err; +} + +static int read_profile_file(const char *fname) +{ + int not_found = INT_MAX; + FILE *fprof; + int err; + + fprof = fopen(fname, "rb"); + if (!fprof) { + error("Cannot open profile data file '%s'\n", + fname); + return 1; + } else { + err = read_profile(fprof, ¬_found); + fclose(fprof); + if (err) + return err; + + if (not_found) { + warn("%d profile functions could not be found in the map file - are you sure that your profile data and map file correspond?\n", + not_found); + return 1; + } + } + return 0; +} + +static int regex_report_error(regex_t *regex, int err, const char *op, + const char *name) +{ + char buf[200]; + + regerror(err, regex, buf, sizeof(buf)); + error("Regex error '%s' in %s '%s'\n", buf, op, name); + return -1; +} + +static void check_trace_config_line(struct trace_configline_info *item) +{ + struct func_info *func, *end; + int err; + + debug("Checking trace config line '%s'\n", item->name); + for (func = func_list, end = func + func_count; func < end; func++) { + err = regexec(&item->regex, func->name, 0, NULL, 0); + debug(" - regex '%s', string '%s': %d\n", item->name, + func->name, err); + if (err == REG_NOMATCH) + continue; + + if (err) { + regex_report_error(&item->regex, err, "match", + item->name); + break; + } + + /* It matches, so perform the action */ + switch (item->type) { + case TRACE_LINE_INCLUDE: + info(" include %s at %lx\n", func->name, + text_offset + func->offset); + func->flags |= FUNCF_TRACE; + break; + + case TRACE_LINE_EXCLUDE: + info(" exclude %s at %lx\n", func->name, + text_offset + func->offset); + func->flags &= ~FUNCF_TRACE; + break; + } + } +} + +static void check_trace_config(void) +{ + struct trace_configline_info *line; + + for (line = trace_config_head; line; line = line->next) + check_trace_config_line(line); +} + +/** + * Check the functions to see if they each have an objsection. If not, then + * the linker must have eliminated them. + */ +static void check_functions(void) +{ + struct func_info *func, *end; + unsigned long removed_code_size = 0; + int not_found = 0; + + /* Look for missing functions */ + for (func = func_list, end = func + func_count; func < end; func++) { + if (!func->objsection) { + removed_code_size += func->code_size; + not_found++; + } + } + + /* Figure out what functions we want to trace */ + check_trace_config(); + + warn("%d functions removed by linker, %ld code size\n", + not_found, removed_code_size); +} + +static int read_trace_config(FILE *fin) +{ + char buff[200]; + int linenum = 0; + struct trace_configline_info **tailp = &trace_config_head; + + while (fgets(buff, sizeof(buff), fin)) { + int len = strlen(buff); + struct trace_configline_info *line; + char *saveptr; + char *s, *tok; + int err; + + linenum++; + if (len && buff[len - 1] == '\n') + buff[len - 1] = '\0'; + + /* skip blank lines and comments */ + for (s = buff; *s == ' ' || *s == '\t'; s++) + ; + if (!*s || *s == '#') + continue; + + line = (struct trace_configline_info *)calloc(1, + sizeof(*line)); + if (!line) { + error("Cannot allocate config line\n"); + return -1; + } + + tok = strtok_r(s, " \t", &saveptr); + if (!tok) { + error("Invalid trace config data on line %d\n", + linenum); + return -1; + } + if (0 == strcmp(tok, "include-func")) { + line->type = TRACE_LINE_INCLUDE; + } else if (0 == strcmp(tok, "exclude-func")) { + line->type = TRACE_LINE_EXCLUDE; + } else { + error("Unknown command in trace config data line %d\n", + linenum); + return -1; + } + + tok = strtok_r(NULL, " \t", &saveptr); + if (!tok) { + error("Missing pattern in trace config data line %d\n", + linenum); + return -1; + } + + err = regcomp(&line->regex, tok, REG_NOSUB); + if (err) { + free(line); + return regex_report_error(&line->regex, err, "compile", + tok); + } + + /* link this new one to the end of the list */ + line->name = strdup(tok); + line->next = NULL; + *tailp = line; + tailp = &line->next; + } + + if (!feof(fin)) { + error("Cannot read from trace config file at position %ld\n", + ftell(fin)); + return -1; + } + return 0; +} + +static int read_trace_config_file(const char *fname) +{ + FILE *fin; + int err; + + fin = fopen(fname, "r"); + if (!fin) { + error("Cannot open trace_config file '%s'\n", fname); + return -1; + } + err = read_trace_config(fin); + fclose(fin); + return err; +} + +static void out_func(ulong func_offset, int is_caller, const char *suffix) +{ + struct func_info *func; + + func = (is_caller ? find_caller_by_offset : find_func_by_offset) + (func_offset); + + if (func) + printf("%s%s", func->name, suffix); + else + printf("%lx%s", func_offset, suffix); +} + +/* + * # tracer: function + * # + * # TASK-PID CPU# TIMESTAMP FUNCTION + * # | | | | | + * # bash-4251 [01] 10152.583854: path_put <-path_walk + * # bash-4251 [01] 10152.583855: dput <-path_put + * # bash-4251 [01] 10152.583855: _atomic_dec_and_lock <-dput + */ +static int make_ftrace(void) +{ + struct trace_call *call; + int missing_count = 0, skip_count = 0; + int i; + + printf("# tracer: ftrace\n" + "#\n" + "# TASK-PID CPU# TIMESTAMP FUNCTION\n" + "# | | | | |\n"); + for (i = 0, call = call_list; i < call_count; i++, call++) { + struct func_info *func = find_func_by_offset(call->func); + ulong time = call->flags & FUNCF_TIMESTAMP_MASK; + + if (TRACE_CALL_TYPE(call) != FUNCF_ENTRY && + TRACE_CALL_TYPE(call) != FUNCF_EXIT) + continue; + if (!func) { + warn("Cannot find function at %lx\n", + text_offset + call->func); + missing_count++; + continue; + } + + if (!(func->flags & FUNCF_TRACE)) { + debug("Funcion '%s' is excluded from trace\n", + func->name); + skip_count++; + continue; + } + + printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1, + time / 1000000, time % 1000000); + + out_func(call->func, 0, " <- "); + out_func(call->caller, 1, "\n"); + } + info("ftrace: %d functions not found, %d excluded\n", missing_count, + skip_count); + + return 0; +} + +static int prof_tool(int argc, char * const argv[], + const char *prof_fname, const char *map_fname, + const char *trace_config_fname) +{ + int err = 0; + + if (read_map_file(map_fname)) + return -1; + if (prof_fname && read_profile_file(prof_fname)) + return -1; + if (trace_config_fname && read_trace_config_file(trace_config_fname)) + return -1; + + check_functions(); + + for (; argc; argc--, argv++) { + const char *cmd = *argv; + + if (0 == strcmp(cmd, "dump-ftrace")) + err = make_ftrace(); + else + warn("Unknown command '%s'\n", cmd); + } + + return err; +} + +int main(int argc, char *argv[]) +{ + const char *map_fname = "System.map"; + const char *prof_fname = NULL; + const char *trace_config_fname = NULL; + int opt; + + verbose = 2; + while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) { + switch (opt) { + case 'm': + map_fname = optarg; + break; + + case 'p': + prof_fname = optarg; + break; + + case 't': + trace_config_fname = optarg; + break; + + case 'v': + verbose = atoi(optarg); + break; + + default: + usage(); + } + } + argc -= optind; argv += optind; + if (argc < 1) + usage(); + + debug("Debug enabled\n"); + return prof_tool(argc, argv, prof_fname, map_fname, + trace_config_fname); +} diff --git a/qemu/roms/u-boot/tools/reformat.py b/qemu/roms/u-boot/tools/reformat.py new file mode 100755 index 000000000..61306d023 --- /dev/null +++ b/qemu/roms/u-boot/tools/reformat.py @@ -0,0 +1,132 @@ +#! /usr/bin/python +######################################################################## +# +# reorder and reformat a file in columns +# +# this utility takes lines from its standard input and reproduces them, +# partially reordered and reformatted, on its standard output. +# +# It has the same effect as a 'sort | column -t', with the exception +# that empty lines, as well as lines which start with a '#' sign, are +# not affected, i.e. they keep their position and formatting, and act +# as separators, i.e. the parts before and after them are each sorted +# separately (but overall field widths are computed across the whole +# input). +# +# Options: +# -i: +# --ignore-case: +# Do not consider case when sorting. +# -d: +# --default: +# What to chage empty fields to. +# -s <N>: +# --split=<N>: +# Treat only the first N whitespace sequences as separators. +# line content after the Nth separator will count as only one +# field even if it contains whitespace. +# Example : '-s 2' causes input 'a b c d e' to be split into +# three fields, 'a', 'b', and 'c d e'. +# +# boards.cfg requires -ids 6. +# +######################################################################## + +import sys, getopt, locale + +# ensure we sort using the C locale. + +locale.setlocale(locale.LC_ALL, 'C') + +# check options + +maxsplit = 0 +ignore_case = 0 +default_field ='' + +try: + opts, args = getopt.getopt(sys.argv[1:], "id:s:", + ["ignore-case","default","split="]) +except getopt.GetoptError as err: + print str(err) # will print something like "option -a not recognized" + sys.exit(2) + +for o, a in opts: + if o in ("-s", "--split"): + maxsplit = eval(a) + elif o in ("-i", "--ignore-case"): + ignore_case = 1 + elif o in ("-d", "--default"): + default_field = a + else: + assert False, "unhandled option" + +# collect all lines from standard input and, for the ones which must be +# reformatted and sorted, count their fields and compute each field's +# maximum size + +input_lines = [] +field_width = [] + +for line in sys.stdin: + # remove final end of line + input_line = line.strip('\n') + if (len(input_line)>0) and (input_line[0] != '#'): + # sortable line: split into fields + fields = input_line.split(None,maxsplit) + # if there are new fields, top up field_widths + for f in range(len(field_width), len(fields)): + field_width.append(0) + # compute the maximum witdh of each field + for f in range(len(fields)): + field_width[f] = max(field_width[f],len(fields[f])) + # collect the line for next stage + input_lines.append(input_line) + +# run through collected input lines, collect the ones which must be +# reformatted and sorted, and whenever a non-reformattable, non-sortable +# line is met, sort the collected lines before it and append them to the +# output lines, then add the non-sortable line too. + +output_lines = [] +sortable_lines = [] +for input_line in input_lines: + if (len(input_line)>0) and (input_line[0] != '#'): + # this line should be reformatted and sorted + input_fields = input_line.split(None,maxsplit) + output_fields = []; + # reformat each field to this field's column width + for f in range(len(input_fields)): + output_field = input_fields[f]; + output_fields.append(output_field.ljust(field_width[f])) + # any missing field is set to default if it exists + if default_field != '': + for f in range(len(input_fields),len(field_width)): + output_fields.append(default_field.ljust(field_width[f])) + # join fields using two spaces, like column -t would + output_line = ' '.join(output_fields); + # collect line for later + sortable_lines.append(output_line) + else: + # this line is non-sortable + # sort collected sortable lines + if ignore_case!=0: + sortable_lines.sort(key=lambda x: str.lower(locale.strxfrm(x))) + else: + sortable_lines.sort(key=lambda x: locale.strxfrm(x)) + # append sortable lines to the final output + output_lines.extend(sortable_lines) + sortable_lines = [] + # append non-sortable line to the final output + output_lines.append(input_line) +# maybe we had sortable lines pending, so append them to the final output +if ignore_case!=0: + sortable_lines.sort(key=lambda x: str.lower(locale.strxfrm(x))) +else: + sortable_lines.sort(key=lambda x: locale.strxfrm(x)) +output_lines.extend(sortable_lines) + +# run through output lines and print them, except rightmost whitespace + +for output_line in output_lines: + print output_line.rstrip() diff --git a/qemu/roms/u-boot/tools/relocate-rela.c b/qemu/roms/u-boot/tools/relocate-rela.c new file mode 100644 index 000000000..670b9fd73 --- /dev/null +++ b/qemu/roms/u-boot/tools/relocate-rela.c @@ -0,0 +1,189 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause + * + * 64-bit and little-endian target only until we need to support a different + * arch that needs this. + */ + +#include <elf.h> +#include <errno.h> +#include <inttypes.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifndef R_AARCH64_RELATIVE +#define R_AARCH64_RELATIVE 1027 +#endif + +static const bool debug_en; + +static void debug(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + if (debug_en) + vprintf(fmt, args); +} + +static bool supported_rela(Elf64_Rela *rela) +{ + uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */ + uint32_t type = rela->r_info & mask; + + switch (type) { +#ifdef R_AARCH64_RELATIVE + case R_AARCH64_RELATIVE: + return true; +#endif + default: + fprintf(stderr, "warning: unsupported relocation type %" + PRIu32 " at %" PRIx64 "\n", + type, rela->r_offset); + + return false; + } +} + +static inline uint64_t swap64(uint64_t val) +{ + return ((val >> 56) & 0x00000000000000ffULL) | + ((val >> 40) & 0x000000000000ff00ULL) | + ((val >> 24) & 0x0000000000ff0000ULL) | + ((val >> 8) & 0x00000000ff000000ULL) | + ((val << 8) & 0x000000ff00000000ULL) | + ((val << 24) & 0x0000ff0000000000ULL) | + ((val << 40) & 0x00ff000000000000ULL) | + ((val << 56) & 0xff00000000000000ULL); +} + +#if __BYTE_ORDER == __LITTLE_ENDIAN +static inline uint64_t be64(uint64_t val) +{ + return swap64(val); +} + +static inline uint64_t le64(uint64_t val) +{ + return val; +} +#else +static inline uint64_t le64(uint64_t val) +{ + return swap64(val); +} + +static inline uint64_t be64(uint64_t val) +{ + return val; +} +#endif + +static bool read_num(const char *str, uint64_t *num) +{ + char *endptr; + *num = strtoull(str, &endptr, 16); + return str[0] && !endptr[0]; +} + +int main(int argc, char **argv) +{ + FILE *f; + int i, num; + uint64_t rela_start, rela_end, text_base; + + if (argc != 5) { + fprintf(stderr, "Statically apply ELF rela relocations\n"); + fprintf(stderr, "Usage: %s <bin file> <text base> " \ + "<rela start> <rela end>\n", argv[0]); + fprintf(stderr, "All numbers in hex.\n"); + return 1; + } + + f = fopen(argv[1], "r+b"); + if (!f) { + fprintf(stderr, "%s: Cannot open %s: %s\n", + argv[0], argv[1], strerror(errno)); + return 2; + } + + if (!read_num(argv[2], &text_base) || + !read_num(argv[3], &rela_start) || + !read_num(argv[4], &rela_end)) { + fprintf(stderr, "%s: bad number\n", argv[0]); + return 3; + } + + if (rela_start > rela_end || rela_start < text_base || + (rela_end - rela_start) % sizeof(Elf64_Rela)) { + fprintf(stderr, "%s: bad rela bounds\n", argv[0]); + return 3; + } + + rela_start -= text_base; + rela_end -= text_base; + + num = (rela_end - rela_start) / sizeof(Elf64_Rela); + + for (i = 0; i < num; i++) { + Elf64_Rela rela, swrela; + uint64_t pos = rela_start + sizeof(Elf64_Rela) * i; + uint64_t addr; + + if (fseek(f, pos, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" PRIx64 + " failed: %s\n", + argv[0], argv[1], pos, strerror(errno)); + } + + if (fread(&rela, sizeof(rela), 1, f) != 1) { + fprintf(stderr, "%s: %s: read rela failed at %" + PRIx64 "\n", + argv[0], argv[1], pos); + return 4; + } + + swrela.r_offset = le64(rela.r_offset); + swrela.r_info = le64(rela.r_info); + swrela.r_addend = le64(rela.r_addend); + + if (!supported_rela(&swrela)) + continue; + + debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n", + swrela.r_offset, swrela.r_info, swrela.r_addend); + + if (swrela.r_offset < text_base) { + fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n", + argv[0], argv[1], pos); + return 4; + } + + addr = swrela.r_offset - text_base; + + if (fseek(f, addr, SEEK_SET) < 0) { + fprintf(stderr, "%s: %s: seek to %" + PRIx64 " failed: %s\n", + argv[0], argv[1], addr, strerror(errno)); + } + + if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) { + fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n", + argv[0], argv[1], addr); + return 4; + } + } + + if (fclose(f) < 0) { + fprintf(stderr, "%s: %s: close failed: %s\n", + argv[0], argv[1], strerror(errno)); + return 4; + } + + return 0; +} diff --git a/qemu/roms/u-boot/tools/rsa-checksum.c b/qemu/roms/u-boot/tools/rsa-checksum.c new file mode 100644 index 000000000..09033e620 --- /dev/null +++ b/qemu/roms/u-boot/tools/rsa-checksum.c @@ -0,0 +1 @@ +#include "../lib/rsa/rsa-checksum.c" diff --git a/qemu/roms/u-boot/tools/rsa-sign.c b/qemu/roms/u-boot/tools/rsa-sign.c new file mode 100644 index 000000000..150bbe151 --- /dev/null +++ b/qemu/roms/u-boot/tools/rsa-sign.c @@ -0,0 +1 @@ +#include "../lib/rsa/rsa-sign.c" diff --git a/qemu/roms/u-boot/tools/rsa-verify.c b/qemu/roms/u-boot/tools/rsa-verify.c new file mode 100644 index 000000000..bb662a1ef --- /dev/null +++ b/qemu/roms/u-boot/tools/rsa-verify.c @@ -0,0 +1 @@ +#include "../lib/rsa/rsa-verify.c" diff --git a/qemu/roms/u-boot/tools/scripts/define2mk.sed b/qemu/roms/u-boot/tools/scripts/define2mk.sed new file mode 100644 index 000000000..c641edfb0 --- /dev/null +++ b/qemu/roms/u-boot/tools/scripts/define2mk.sed @@ -0,0 +1,35 @@ +# +# Sed script to parse CPP macros and generate output usable by make +# +# It is expected that this script is fed the output of 'gpp -dM' +# which preprocesses the common.h header files and outputs the final +# list of CPP macros (and whitespace is sanitized) +# + +# Only process values prefixed with #define CONFIG_ +/^#define CONFIG_[A-Za-z0-9_][A-Za-z0-9_]*/ { + # Strip the #define prefix + s/#define *//; + # Change to form CONFIG_*=VALUE + s/ */=/; + # Drop trailing spaces + s/ *$//; + # drop quotes around string values + s/="\(.*\)"$/=\1/; + # Concatenate string values + s/" *"//g; + # Assume strings as default - add quotes around values + s/=\(..*\)/="\1"/; + # but remove again from decimal numbers + s/="\([0-9][0-9]*\)"/=\1/; + # ... and from hex numbers + s/="\(0[Xx][0-9a-fA-F][0-9a-fA-F]*\)"/=\1/; + # ... and from configs defined from other configs + s/="\(CONFIG_[A-Za-z0-9_][A-Za-z0-9_]*\)"/=$(\1)/; + # Change '1' and empty values to "y" (not perfect, but + # supports conditional compilation in the makefiles + s/=$/=y/; + s/=1$/=y/; + # print the line + p +} diff --git a/qemu/roms/u-boot/tools/sha1.c b/qemu/roms/u-boot/tools/sha1.c new file mode 100644 index 000000000..0d717dfa4 --- /dev/null +++ b/qemu/roms/u-boot/tools/sha1.c @@ -0,0 +1 @@ +#include "../lib/sha1.c" diff --git a/qemu/roms/u-boot/tools/sha256.c b/qemu/roms/u-boot/tools/sha256.c new file mode 100644 index 000000000..8ca931f6b --- /dev/null +++ b/qemu/roms/u-boot/tools/sha256.c @@ -0,0 +1 @@ +#include "../lib/sha256.c" diff --git a/qemu/roms/u-boot/tools/ublimage.c b/qemu/roms/u-boot/tools/ublimage.c new file mode 100644 index 000000000..cbbbe205d --- /dev/null +++ b/qemu/roms/u-boot/tools/ublimage.c @@ -0,0 +1,261 @@ +/* + * (C) Copyright 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * Based on: + * (C) Copyright 2009 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * (C) Copyright 2008 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "imagetool.h" +#include <image.h> +#include "ublimage.h" + +/* + * Supported commands for configuration file + */ +static table_entry_t ublimage_cmds[] = { + {CMD_BOOT_MODE, "MODE", "UBL special modes", }, + {CMD_ENTRY, "ENTRY", "Entry point addr for bootloader", }, + {CMD_PAGE, "PAGES", + "number of pages (size of bootloader)", }, + {CMD_ST_BLOCK, "START_BLOCK", + "block number where bootloader is present", }, + {CMD_ST_PAGE, "START_PAGE", + "page number where bootloader is present", }, + {CMD_LD_ADDR, "LD_ADDR", + "load addr", }, + {-1, "", "", }, +}; + +/* + * Supported Boot options for configuration file + * this is needed to set the correct flash offset + */ +static table_entry_t ublimage_bootops[] = { + {UBL_MAGIC_SAFE, "safe", "Safe boot mode", }, + {-1, "", "Invalid", }, +}; + +static struct ubl_header ublimage_header; + +static uint32_t get_cfg_value(char *token, char *name, int linenr) +{ + char *endptr; + uint32_t value; + + errno = 0; + value = strtoul(token, &endptr, 16); + if (errno || (token == endptr)) { + fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", + name, linenr, token); + exit(EXIT_FAILURE); + } + return value; +} + +static void print_hdr(struct ubl_header *ubl_hdr) +{ + printf("Image Type : Davinci UBL Boot Image\n"); + printf("UBL magic : %08x\n", ubl_hdr->magic); + printf("Entry Point: %08x\n", ubl_hdr->entry); + printf("nr of pages: %08x\n", ubl_hdr->pages); + printf("start block: %08x\n", ubl_hdr->block); + printf("start page : %08x\n", ubl_hdr->page); +} + +static void parse_cfg_cmd(struct ubl_header *ublhdr, int32_t cmd, char *token, + char *name, int lineno, int fld, int dcd_len) +{ + static int cmd_ver_first = ~0; + + switch (cmd) { + case CMD_BOOT_MODE: + ublhdr->magic = get_table_entry_id(ublimage_bootops, + "ublimage special boot mode", token); + if (ublhdr->magic == -1) { + fprintf(stderr, "Error: %s[%d] -Invalid boot mode" + "(%s)\n", name, lineno, token); + exit(EXIT_FAILURE); + } + ublhdr->magic += UBL_MAGIC_BASE; + if (unlikely(cmd_ver_first != 1)) + cmd_ver_first = 0; + break; + case CMD_ENTRY: + ublhdr->entry = get_cfg_value(token, name, lineno); + break; + case CMD_PAGE: + ublhdr->pages = get_cfg_value(token, name, lineno); + break; + case CMD_ST_BLOCK: + ublhdr->block = get_cfg_value(token, name, lineno); + break; + case CMD_ST_PAGE: + ublhdr->page = get_cfg_value(token, name, lineno); + break; + case CMD_LD_ADDR: + ublhdr->pll_m = get_cfg_value(token, name, lineno); + break; + } +} + +static void parse_cfg_fld(struct ubl_header *ublhdr, int32_t *cmd, + char *token, char *name, int lineno, int fld, int *dcd_len) +{ + + switch (fld) { + case CFG_COMMAND: + *cmd = get_table_entry_id(ublimage_cmds, + "ublimage commands", token); + if (*cmd < 0) { + fprintf(stderr, "Error: %s[%d] - Invalid command" + "(%s)\n", name, lineno, token); + exit(EXIT_FAILURE); + } + break; + case CFG_REG_VALUE: + parse_cfg_cmd(ublhdr, *cmd, token, name, lineno, fld, *dcd_len); + break; + default: + break; + } +} +static uint32_t parse_cfg_file(struct ubl_header *ublhdr, char *name) +{ + FILE *fd = NULL; + char *line = NULL; + char *token, *saveptr1, *saveptr2; + int lineno = 0; + int i; + char *ptr = (char *)ublhdr; + int fld; + size_t len; + int dcd_len = 0; + int32_t cmd; + int ublhdrlen = sizeof(struct ubl_header); + + fd = fopen(name, "r"); + if (fd == 0) { + fprintf(stderr, "Error: %s - Can't open DCD file\n", name); + exit(EXIT_FAILURE); + } + + /* Fill header with 0xff */ + for (i = 0; i < ublhdrlen; i++) { + *ptr = 0xff; + ptr++; + } + + /* + * Very simple parsing, line starting with # are comments + * and are dropped + */ + while ((getline(&line, &len, fd)) > 0) { + lineno++; + + token = strtok_r(line, "\r\n", &saveptr1); + if (token == NULL) + continue; + + /* Check inside the single line */ + for (fld = CFG_COMMAND, cmd = CMD_INVALID, + line = token; ; line = NULL, fld++) { + token = strtok_r(line, " \t", &saveptr2); + if (token == NULL) + break; + + /* Drop all text starting with '#' as comments */ + if (token[0] == '#') + break; + + parse_cfg_fld(ublhdr, &cmd, token, name, + lineno, fld, &dcd_len); + } + } + fclose(fd); + + return dcd_len; +} + +static int ublimage_check_image_types(uint8_t type) +{ + if (type == IH_TYPE_UBLIMAGE) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +} + +static int ublimage_verify_header(unsigned char *ptr, int image_size, + struct image_tool_params *params) +{ + struct ubl_header *ubl_hdr = (struct ubl_header *)ptr; + + if ((ubl_hdr->magic & 0xFFFFFF00) != UBL_MAGIC_BASE) + return -1; + + return 0; +} + +static void ublimage_print_header(const void *ptr) +{ + struct ubl_header *ubl_hdr = (struct ubl_header *) ptr; + + print_hdr(ubl_hdr); +} + +static void ublimage_set_header(void *ptr, struct stat *sbuf, int ifd, + struct image_tool_params *params) +{ + struct ubl_header *ublhdr = (struct ubl_header *)ptr; + + /* Parse configuration file */ + parse_cfg_file(ublhdr, params->imagename); +} + +int ublimage_check_params(struct image_tool_params *params) +{ + if (!params) + return CFG_INVALID; + if (!strlen(params->imagename)) { + fprintf(stderr, "Error: %s - Configuration file not" + "specified, it is needed for ublimage generation\n", + params->cmdname); + return CFG_INVALID; + } + /* + * Check parameters: + * XIP is not allowed and verify that incompatible + * parameters are not sent at the same time + * For example, if list is required a data image must not be provided + */ + return (params->dflag && (params->fflag || params->lflag)) || + (params->fflag && (params->dflag || params->lflag)) || + (params->lflag && (params->dflag || params->fflag)) || + (params->xflag) || !(strlen(params->imagename)); +} + +/* + * ublimage parameters + */ +static struct image_type_params ublimage_params = { + .name = "Davinci UBL boot support", + .header_size = sizeof(struct ubl_header), + .hdr = (void *)&ublimage_header, + .check_image_type = ublimage_check_image_types, + .verify_header = ublimage_verify_header, + .print_header = ublimage_print_header, + .set_header = ublimage_set_header, + .check_params = ublimage_check_params, +}; + +void init_ubl_image_type(void) +{ + register_image_type(&ublimage_params); +} diff --git a/qemu/roms/u-boot/tools/ublimage.h b/qemu/roms/u-boot/tools/ublimage.h new file mode 100644 index 000000000..32cc5822c --- /dev/null +++ b/qemu/roms/u-boot/tools/ublimage.h @@ -0,0 +1,84 @@ +/* + * (C) Copyright 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * Vased on: + * (C) Copyright 2009 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _UBLIMAGE_H_ +#define _UBLIMAGE_H_ + +enum ublimage_cmd { + CMD_INVALID, + CMD_BOOT_MODE, + CMD_ENTRY, + CMD_PAGE, + CMD_ST_BLOCK, + CMD_ST_PAGE, + CMD_LD_ADDR +}; + +enum ublimage_fld_types { + CFG_INVALID = -1, + CFG_COMMAND, + CFG_REG_VALUE +}; + +/* + * from sprufg5a.pdf Table 110 + * Used by RBL when doing NAND boot + */ +#define UBL_MAGIC_BASE (0xA1ACED00) +/* Safe boot mode */ +#define UBL_MAGIC_SAFE (0x00) +/* DMA boot mode */ +#define UBL_MAGIC_DMA (0x11) +/* I Cache boot mode */ +#define UBL_MAGIC_IC (0x22) +/* Fast EMIF boot mode */ +#define UBL_MAGIC_FAST (0x33) +/* DMA + ICache boot mode */ +#define UBL_MAGIC_DMA_IC (0x44) +/* DMA + ICache + Fast EMIF boot mode */ +#define UBL_MAGIC_DMA_IC_FAST (0x55) + +/* Define max UBL image size */ +#define UBL_IMAGE_SIZE (0x00003800u) + +/* one NAND block */ +#define UBL_BLOCK_SIZE 2048 + +/* from sprufg5a.pdf Table 109 */ +struct ubl_header { + uint32_t magic; /* Magic Number, see UBL_* defines */ + uint32_t entry; /* entry point address for bootloader */ + uint32_t pages; /* number of pages (size of bootloader) */ + uint32_t block; /* + * blocknumber where user bootloader is + * present + */ + uint32_t page; /* + * page number where user bootloader is + * present. + */ + uint32_t pll_m; /* + * PLL setting -Multiplier (only valid if + * Magic Number indicates PLL enable). + */ + uint32_t pll_n; /* + * PLL setting -Divider (only valid if + * Magic Number indicates PLL enable). + */ + uint32_t emif; /* + * fast EMIF setting (only valid if + * Magic Number indicates fast EMIF boot). + */ + /* to fit in one nand block */ + unsigned char res[UBL_BLOCK_SIZE - 8 * 4]; +}; + +#endif /* _UBLIMAGE_H_ */ diff --git a/qemu/roms/u-boot/tools/ubsha1.c b/qemu/roms/u-boot/tools/ubsha1.c new file mode 100644 index 000000000..1041588d0 --- /dev/null +++ b/qemu/roms/u-boot/tools/ubsha1.c @@ -0,0 +1,84 @@ +/* + * (C) Copyright 2007 + * Heiko Schocher, DENX Software Engineering, <hs@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "os_support.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <string.h> +#include <sys/stat.h> +#include "sha1.h" + +int main (int argc, char **argv) +{ + unsigned char output[20]; + int i, len; + + char *imagefile; + char *cmdname = *argv; + unsigned char *ptr; + unsigned char *data; + struct stat sbuf; + unsigned char *ptroff; + int ifd; + int off; + + if (argc > 1) { + imagefile = argv[1]; + ifd = open (imagefile, O_RDWR|O_BINARY); + if (ifd < 0) { + fprintf (stderr, "%s: Can't open %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + if (fstat (ifd, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + len = sbuf.st_size; + ptr = (unsigned char *)mmap(0, len, + PROT_READ, MAP_SHARED, ifd, 0); + if (ptr == (unsigned char *)MAP_FAILED) { + fprintf (stderr, "%s: Can't read %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + /* create a copy, so we can blank out the sha1 sum */ + data = malloc (len); + memcpy (data, ptr, len); + off = SHA1_SUM_POS; + ptroff = &data[len + off]; + for (i = 0; i < SHA1_SUM_LEN; i++) { + ptroff[i] = 0; + } + + sha1_csum ((unsigned char *) data, len, (unsigned char *)output); + + printf ("U-Boot sum:\n"); + for (i = 0; i < 20 ; i++) { + printf ("%02X ", output[i]); + } + printf ("\n"); + /* overwrite the sum in the bin file, with the actual */ + lseek (ifd, SHA1_SUM_POS, SEEK_END); + if (write (ifd, output, SHA1_SUM_LEN) != SHA1_SUM_LEN) { + fprintf (stderr, "%s: Can't write %s: %s\n", + cmdname, imagefile, strerror(errno)); + exit (EXIT_FAILURE); + } + + free (data); + (void) munmap((void *)ptr, len); + (void) close (ifd); + } + + return EXIT_SUCCESS; +} diff --git a/qemu/roms/u-boot/tools/xway-swap-bytes.c b/qemu/roms/u-boot/tools/xway-swap-bytes.c new file mode 100644 index 000000000..3a6d82d54 --- /dev/null +++ b/qemu/roms/u-boot/tools/xway-swap-bytes.c @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifndef BUFSIZ +# define BUFSIZ 4096 +#endif + +#undef BUFSIZ +# define BUFSIZ 64 +int main (void) +{ + short ibuff[BUFSIZ], obuff[BUFSIZ]; + int rc, i, len; + + while ((rc = read (0, ibuff, sizeof (ibuff))) > 0) { + memset (obuff, 0, sizeof (obuff)); + for (i = 0; i < (rc + 1) / 2; i++) { + obuff[i] = ibuff[i ^ 1]; + } + + len = (rc + 1) & ~1; + + if (write (1, obuff, len) != len) { + perror ("read error"); + return (EXIT_FAILURE); + } + + memset (ibuff, 0, sizeof (ibuff)); + } + + if (rc < 0) { + perror ("read error"); + return (EXIT_FAILURE); + } + return (EXIT_SUCCESS); +} |