diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/Makefile | 9 | ||||
-rw-r--r-- | tools/mkexynosspl.c | 167 | ||||
-rw-r--r-- | tools/mxsimage.c | 1 | ||||
-rw-r--r-- | tools/relocate-rela.c | 189 |
4 files changed, 322 insertions, 44 deletions
diff --git a/tools/Makefile b/tools/Makefile index e1264fd..328cea3 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -54,12 +54,14 @@ BIN_FILES-y += dumpimage$(SFX) BIN_FILES-y += mkenvimage$(SFX) BIN_FILES-y += mkimage$(SFX) BIN_FILES-$(CONFIG_EXYNOS5250) += mk$(BOARD)spl$(SFX) +BIN_FILES-$(CONFIG_EXYNOS5420) += mk$(BOARD)spl$(SFX) BIN_FILES-$(CONFIG_MX23) += mxsboot$(SFX) BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX) BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX) BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX) BIN_FILES-$(CONFIG_KIRKWOOD) += kwboot$(SFX) BIN_FILES-y += proftool(SFX) +BIN_FILES-$(CONFIG_STATIC_RELA) += relocate-rela$(SFX) # Source files which exist outside the tools directory EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o @@ -87,10 +89,11 @@ NOPED_OBJ_FILES-y += os_support.o NOPED_OBJ_FILES-y += pblimage.o NOPED_OBJ_FILES-y += proftool.o NOPED_OBJ_FILES-y += ublimage.o +NOPED_OBJ_FILES-y += relocate-rela.o OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc.o OBJ_FILES-$(CONFIG_CMD_LOADS) += img2srec.o OBJ_FILES-$(CONFIG_CMD_NET) += gen_eth_addr.o -OBJ_FILES-$(CONFIG_EXYNOS5250) += mkexynosspl.o +OBJ_FILES-$(CONFIG_EXYNOS_SPL) += mkexynosspl.o OBJ_FILES-$(CONFIG_KIRKWOOD) += kwboot.o OBJ_FILES-$(CONFIG_LCD_LOGO) += bmp_logo.o OBJ_FILES-$(CONFIG_MX23) += mxsboot.o @@ -278,6 +281,10 @@ $(obj)kwboot$(SFX): $(obj)kwboot.o $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTSTRIP) $@ +$(obj)relocate-rela$(SFX): $(obj)relocate-rela.o + $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ + $(HOSTSTRIP) $@ + # Some of the tool objects need to be accessed from outside the tools directory $(obj)%.o: $(SRCTREE)/common/%.c $(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $< diff --git a/tools/mkexynosspl.c b/tools/mkexynosspl.c index ef685b7..32b786c 100644 --- a/tools/mkexynosspl.c +++ b/tools/mkexynosspl.c @@ -14,93 +14,174 @@ #include <compiler.h> #define CHECKSUM_OFFSET (14*1024-4) -#define BUFSIZE (14*1024) #define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP \ | S_IWGRP | S_IROTH | S_IWOTH) /* -* Requirement: -* IROM code reads first 14K bytes from boot device. -* It then calculates the checksum of 14K-4 bytes and compare with data at -* 14K-4 offset. -* -* This function takes two filenames: -* IN "u-boot-spl.bin" and -* OUT "$(BOARD)-spl.bin as filenames. -* It reads the "u-boot-spl.bin" in 16K buffer. -* It calculates checksum of 14K-4 Bytes and stores at 14K-4 offset in buffer. -* It writes the buffer to "$(BOARD)-spl.bin" file. -*/ + * 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[BUFSIZE]; + unsigned char *buffer; int i, ifd, ofd; uint32_t checksum = 0; off_t len; - ssize_t count; + int var_size_flag, read_size, count; struct stat stat; - - if (argc != 3) { - fprintf(stderr, "Usage: %s <infile> <outfile>\n", argv[0]); + 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); } - ifd = open(argv[1], O_RDONLY); + /* 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", - argv[0], argv[1], strerror(errno)); + prog_name, argv[if_index], strerror(errno)); exit(EXIT_FAILURE); } - ofd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM); + 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", - argv[0], argv[2], strerror(errno)); - close(ifd); + 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", - argv[0], argv[1], strerror(errno)); - close(ifd); - close(ofd); + prog_name, argv[if_index], strerror(errno)); exit(EXIT_FAILURE); } len = stat.st_size; - count = (len < CHECKSUM_OFFSET) ? len : CHECKSUM_OFFSET; - - if (read(ifd, buffer, count) != count) { - fprintf(stderr, "%s: Can't read %s: %s\n", - argv[0], argv[1], strerror(errno)); + 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; + } - close(ifd); - close(ofd); + 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); } - for (i = 0, checksum = 0; i < CHECKSUM_OFFSET; i++) - checksum += buffer[i]; + /* 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); - memcpy(&buffer[CHECKSUM_OFFSET], &checksum, sizeof(checksum)); - - if (write(ofd, buffer, BUFSIZE) != BUFSIZE) { - fprintf(stderr, "%s: Can't write %s: %s\n", - argv[0], argv[2], strerror(errno)); + if (var_size_flag) { + /* Prepare and write out the variable size SPL header. */ + struct var_size_header vsh; + uint32_t spl_size; - close(ifd); - close(ofd); + memset(&vsh, 0, sizeof(vsh)); + memcpy(&vsh.spl_checksum, &checksum, sizeof(checksum)); - exit(EXIT_FAILURE); + 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/tools/mxsimage.c b/tools/mxsimage.c index b214050..045b35a 100644 --- a/tools/mxsimage.c +++ b/tools/mxsimage.c @@ -502,6 +502,7 @@ static int sb_token_to_long(char *tok, uint32_t *rid) 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"); diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c new file mode 100644 index 0000000..93b4c39 --- /dev/null +++ b/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) % 24) { + 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; +} |