Message ID | 20201028141003.3062021-5-sr@denx.de |
---|---|
State | Superseded |
Delegated to: | Daniel Schwierzeck |
Headers | show |
Series | [1/5,v2] mips: start.S: Add Octeon boot header compatibility | expand |
Am Mittwoch, den 28.10.2020, 15:10 +0100 schrieb Stefan Roese: > Add a tool to update or insert an Octeon specific header into the U-Boot > image. This is needed e.g. for booting via SPI NOR, eMMC and NAND. > > While working on this, move enum cvmx_board_types_enum and > cvmx_board_type_to_string() to cvmx-bootloader.h and remove the > unreferenced (unsupported) board definition. > > Signed-off-by: Stefan Roese <sr@denx.de> > Cc: Aaron Williams <awilliams@marvell.com> > Cc: Chandrakala Chavva <cchavva@marvell.com> > Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> > --- > v2: > - No change > - Azure build success here: > https://dev.azure.com/sr0718/u-boot/_build/results?buildId=59&view=results > > .../mach-octeon/include/mach/cvmx-bootinfo.h | 222 --------- > .../include/mach/cvmx-bootloader.h | 172 +++++++ > tools/Makefile | 3 + > tools/update_octeon_header.c | 450 ++++++++++++++++++ > 4 files changed, 625 insertions(+), 222 deletions(-) > create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-bootloader.h > create mode 100644 tools/update_octeon_header.c > ... > diff --git a/tools/Makefile b/tools/Makefile > index 51123fd929..253a6b9706 100644 > --- a/tools/Makefile > +++ b/tools/Makefile > @@ -206,6 +206,9 @@ hostprogs-y += proftool > hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela > hostprogs-$(CONFIG_RISCV) += prelink-riscv > > +hostprogs-$(CONFIG_ARCH_OCTEON) += update_octeon_header > +update_octeon_header-objs := update_octeon_header.o lib/crc32.o entry in tools/.gitignore is missing > + > hostprogs-y += fdtgrep > fdtgrep-objs += $(LIBFDT_OBJS) common/fdt_region.o fdtgrep.o > > diff --git a/tools/update_octeon_header.c b/tools/update_octeon_header.c > new file mode 100644 > index 0000000000..964036216d > --- /dev/null > +++ b/tools/update_octeon_header.c > @@ -0,0 +1,450 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (C) 2020 Marvell International Ltd. > + */ > + > +#include <stdio.h> > +#include <stdint.h> > +#include <stddef.h> > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <fcntl.h> > +#include <unistd.h> > +#include <stdlib.h> > +#include <string.h> > +#include <getopt.h> > +#include <arpa/inet.h> > + > +#include <u-boot/crc.h> > + > +#include "mkimage.h" > + > +#include "../arch/mips/mach-octeon/include/mach/cvmx-bootloader.h" > + > +void usage(void); this needs some code cleanup: - drop the forward declarations and reorder the functions when necessary - make all functions static - drop dead code - drop debug() macros convert the useful ones to printf - maybe use fprintf(STDERR, ...) for error messages there are also some bugs: - tool crashes with segfault when called without arguments - tool crashes when called with a long option but no value - the bugs above will also be detected by clang-tidy, suggestions for fixing below > + > +/* > + * Do some funky stuff here to get a compile time error if the size of the > + * bootloader_header structure has changed. > + */ > +#define compile_time_assert(cond, msg) char msg[(cond) ? 1 : -1] > +compile_time_assert(sizeof(struct bootloader_header) == 192, > + bootloader_header_size_changed); there is BUILD_BUG_ON_MSG() in linux/build_bug.h or compiletime_assert() in linux/compiler.h > + > +#define BUF_SIZE (16 * 1024) > +#define NAME_LEN 100 > + > +#ifndef WOFFSETOF > +/* word offset */ > +#define WOFFSETOF(type, elem) (offsetof(type, elem) / 4) > +#endif > + > +#define cvmx_cpu_to_be64(x) (x) > + > +static int stage2_flag; > +static int stage_1_5_flag; > +static int stage_1_flag; > + > +int lookup_board_type(char *board_name) > +{ > + int i; > + int board_type = 0; > + char *substr = NULL; > + > + /* Detect stage 2 bootloader boards */ > + if (strcasestr(board_name, "_stage2")) { > + debug("Stage 2 bootloader detected from substring %s in name %s\n", > + "_stage2", board_name); > + stage2_flag = 1; > + } else { > + debug("Stage 2 bootloader NOT detected from name \"%s\"\n", > + board_name); > + } > + > + if (strcasestr(board_name, "_stage1")) { > + debug("Stage 1 bootloader detected from substring %s in name %s\n", > + "_stage1", board_name); > + stage_1_flag = 1; > + } > + > + /* Generic is a special case since there are numerous sub-types */ > + if (!strncasecmp("generic", board_name, strlen("generic"))) > + return CVMX_BOARD_TYPE_GENERIC; > + > + /* > + * If we're an eMMC stage 2 bootloader, cut off the _emmc_stage2 > + * part of the name. > + */ > + substr = strcasestr(board_name, "_emmc_stage2"); > + if (substr && (substr[strlen("_emmc_stage2")] == '\0')) { > + /*return CVMX_BOARD_TYPE_GENERIC;*/ > + > + printf(" Converting board name %s to ", board_name); > + *substr = '\0'; > + printf("%s\n", board_name); > + } > + > + /* > + * If we're a NAND stage 2 bootloader, cut off the _nand_stage2 > + * part of the name. > + */ > + substr = strcasestr(board_name, "_nand_stage2"); > + if (substr && (substr[strlen("_nand_stage2")] == '\0')) { > + /*return CVMX_BOARD_TYPE_GENERIC;*/ > + > + printf(" Converting board name %s to ", board_name); > + *substr = '\0'; > + printf("%s\n", board_name); > + } > + > + /* > + * If we're a SPI stage 2 bootloader, cut off the _spi_stage2 > + * part of the name. > + */ > + substr = strcasestr(board_name, "_spi_stage2"); > + if (substr && (substr[strlen("_spi_stage2")] == '\0')) { > + printf(" Converting board name %s to ", board_name); > + *substr = '\0'; > + printf("%s\n", board_name); > + } > + > + for (i = CVMX_BOARD_TYPE_NULL; i < CVMX_BOARD_TYPE_MAX; i++) > + if (!strcasecmp(cvmx_board_type_to_string(i), board_name)) > + board_type = i; > + > + for (i = CVMX_BOARD_TYPE_CUST_DEFINED_MIN; > + i < CVMX_BOARD_TYPE_CUST_DEFINED_MAX; i++) > + if (!strncasecmp(cvmx_board_type_to_string(i), board_name, > + strlen(cvmx_board_type_to_string(i)))) > + board_type = i; > + > + for (i = CVMX_BOARD_TYPE_CUST_PRIVATE_MIN; > + i < CVMX_BOARD_TYPE_CUST_PRIVATE_MAX; i++) > + if (!strncasecmp(cvmx_board_type_to_string(i), board_name, > + strlen(cvmx_board_type_to_string(i)))) > + board_type = i; > + > + return board_type; > +} > + > +/* Getoptions variables must be global */ > +static int failsafe_flag; > +static int pciboot_flag; > +static int env_flag; > + > +int main(int argc, char *argv[]) > +{ > + int fd; > + uint8_t buf[BUF_SIZE]; > + uint32_t data_crc = 0; > + int len; > + int data_len = 0; > + struct bootloader_header header; > + char filename[NAME_LEN]; > + int i; > + int option_index = 0; /* getopt_long stores the option index here. */ > + char board_name[NAME_LEN] = { 0 }; > + char tmp_board_name[NAME_LEN] = { 0 }; > + int c; > + int board_type = 0; > + unsigned long long address = 0; > + ssize_t ret; > + const char *type_str = NULL; > + int hdr_size = sizeof(struct bootloader_header); the tool has two positional arguments, so you should bail out early. This will also fix the segfault if (argc < 3) { usage(); return -1; } > + > + debug("header size is: %d bytes\n", hdr_size); > + > + /* Parse command line options using getopt_long */ > + while (1) { > + static struct option long_options[] = { > + /* These options set a flag. */ > + {"failsafe", no_argument, &failsafe_flag, 1}, > + {"pciboot", no_argument, &pciboot_flag, 1}, > + {"nandstage2", no_argument, &stage2_flag, 1}, > + {"spistage2", no_argument, &stage2_flag, 1}, > + {"norstage2", no_argument, &stage2_flag, 1}, > + {"stage2", no_argument, &stage2_flag, 1}, > + {"stage1.5", no_argument, &stage_1_5_flag, 1}, > + {"stage1", no_argument, &stage_1_flag, 1}, > + {"environment", no_argument, &env_flag, 1}, > + /* These options don't set a flag. > + * We distinguish them by their indices. > + */ > + {"board", required_argument, 0, 0}, > + {"text_base", required_argument, 0, 0}, > + {0, 0, 0, 0} > + }; this should be moved out of main() and marked as static const > + > + c = getopt_long(argc, (char *const *)argv, "h", cast is not needed > + long_options, &option_index); > + > + /* Detect the end of the options. */ > + if (c == -1) > + break; > + > + switch (c) { > + /* All long options handled in case 0 */ > + case 0: > + /* If this option set a flag, do nothing else now. */ > + if (long_options[option_index].flag != 0) > + break; > + debug("option(l) %s", long_options[option_index].name); > + if (optarg) > + debug(" with arg %s", optarg); > + debug("\n"); should be if (!optarg) { usage(); return -1; } debug(" with arg %s\n", optarg); the code below depends on optarg and passing a long option without value is an error and should be notified to the user > + > + if (!strcmp(long_options[option_index].name, "board")) { > + if (strlen(optarg) >= NAME_LEN) { > + printf("strncpy() issue detected!"); > + exit(-1); > + } > + strncpy(board_name, optarg, NAME_LEN); > + > + debug("Using user supplied board name: %s\n", > + board_name); > + } else if (!strcmp(long_options[option_index].name, > + "text_base")) { > + address = strtoull(optarg, NULL, 0); > + debug("Address of image is: 0x%llx\n", > + (unsigned long long)address); > + if (!(address & 0xFFFFFFFFULL << 32)) { > + if (address & 1 << 31) { > + address |= 0xFFFFFFFFULL << 32; > + debug("Converting address to 64 bit compatibility space: 0x%llx\n", > + address); > + } > + } > + } > + break; > + > + case 'h': > + case '?': > + /* getopt_long already printed an error message. */ > + usage(); > + return -1; > + > + default: > + abort(); > + } > + } > + > + if (optind < argc) { > + /* > + * We only support one argument - an optional bootloader > + * file name > + */ > + if (argc - optind > 2) { > + debug("non-option ARGV-elements: "); > + while (optind < argc) > + debug("%s ", argv[optind++]); > + debug("\n"); > + usage(); > + return -1; > + } > + } > + > + if (strlen(argv[optind]) >= NAME_LEN) { > + printf("strncpy() issue detected!"); > + exit(-1); > + } > + strncpy(filename, argv[optind], NAME_LEN); > + > + if (board_name[0] == '\0') { > + if (strlen(argv[optind + 1]) >= NAME_LEN) { > + printf("strncpy() issue detected!"); > + exit(-1); > + } > + strncpy(board_name, argv[optind + 1], NAME_LEN); > + } > + > + if (strlen(board_name) >= NAME_LEN) { > + printf("strncpy() issue detected!"); > + exit(-1); > + } > + strncpy(tmp_board_name, board_name, NAME_LEN); > + > + fd = open(filename, O_RDWR); > + if (fd < 0) { > + printf("Unable to open file: %s\n", filename); > + exit(-1); > + } > + > + if (failsafe_flag) > + debug("Setting failsafe flag\n"); > + > + if (strlen(board_name)) { > + int offset = 0; > + > + debug("Supplied board name of: %s\n", board_name); > + > + if (strstr(board_name, "failsafe")) { > + failsafe_flag = 1; > + debug("Setting failsafe flag based on board name\n"); > + } > + /* Skip leading octeon_ if present. */ > + if (!strncmp(board_name, "octeon_", 7)) > + offset = 7; > + > + /* > + * Check to see if 'failsafe' is in the name. If so, set the > + * failsafe flag. Also, ignore extra trailing characters on > + * passed parameter when comparing against board names. > + * We actually use the configuration name from u-boot, so it > + * may have some other variant names. Variants other than > + * failsafe _must_ be passed to this program explicitly > + */ > + > + board_type = lookup_board_type(board_name + offset); > + if (!board_type) { > + /* Retry with 'cust_' prefix to catch boards that are > + * in the customer section (such as nb5) > + */ > + sprintf(tmp_board_name, "cust_%s", board_name + offset); > + board_type = lookup_board_type(tmp_board_name); > + } > + > + /* reset to original value */ > + strncpy(tmp_board_name, board_name, NAME_LEN); > + if (!board_type) { > + /* > + * Retry with 'cust_private_' prefix to catch boards > + * that are in the customer private section > + */ > + sprintf(tmp_board_name, "cust_private_%s", > + board_name + offset); > + board_type = lookup_board_type(tmp_board_name); > + } > + > + if (!board_type) { > + printf("ERROR: unable to determine board type\n"); > + exit(-1); > + } > + debug("Board type is: %d: %s\n", board_type, > + cvmx_board_type_to_string(board_type)); > + } else { > + printf("Board name must be specified!\n"); > + exit(-1); > + } > + > + /* > + * Check to see if there is either an existing header, or that there > + * are zero valued bytes where we want to put the header > + */ > + len = read(fd, buf, BUF_SIZE); > + if (len > 0) { > + /* > + * Copy the header, as the first word (jump instruction, needs > + * to remain the same. > + */ > + memcpy(&header, buf, hdr_size); > + /* > + * Check to see if we have zero bytes (excluding first 4, which > + * are the jump instruction) > + */ > + for (i = 1; i < hdr_size / 4; i++) { > + if (((uint32_t *)buf)[i]) { > + printf("ERROR: non-zero word found %x in location %d required for header, aborting\n", > + ((uint32_t *)buf)[i], i); > + exit(-1); > + } > + } > + debug("Zero bytes found in header location, adding header.\n"); > + > + } else { > + printf("Unable to read from file %s\n", filename); > + exit(-1); > + } > + > + /* Read data bytes and generate CRC */ > + lseek(fd, hdr_size, SEEK_SET); > + > + while ((len = read(fd, buf, BUF_SIZE)) > 0) { > + data_crc = crc32(data_crc, buf, len); > + data_len += len; > + } > + printf("CRC of data: 0x%x, length: %d\n", data_crc, data_len); > + > + /* Now create the new header */ > + header.magic = htonl(BOOTLOADER_HEADER_MAGIC); > + header.maj_rev = htons(BOOTLOADER_HEADER_CURRENT_MAJOR_REV); > + header.min_rev = htons(BOOTLOADER_HEADER_CURRENT_MINOR_REV); > + header.dlen = htonl(data_len); > + header.dcrc = htonl(data_crc); > + header.board_type = htons(board_type); > + header.address = cvmx_cpu_to_be64(address); cvmx_cpu_to_be64() is a no-op, is this intentional? If yes, this macro can be removed. Otherwise you can use cpu_to_be64(). All cpu_to_be*() functions are automatically available in tools/ directory.
Hi Daniel, On 27.11.20 20:01, Daniel Schwierzeck wrote: > Am Mittwoch, den 28.10.2020, 15:10 +0100 schrieb Stefan Roese: >> Add a tool to update or insert an Octeon specific header into the U-Boot >> image. This is needed e.g. for booting via SPI NOR, eMMC and NAND. >> >> While working on this, move enum cvmx_board_types_enum and >> cvmx_board_type_to_string() to cvmx-bootloader.h and remove the >> unreferenced (unsupported) board definition. >> >> Signed-off-by: Stefan Roese <sr@denx.de> >> Cc: Aaron Williams <awilliams@marvell.com> >> Cc: Chandrakala Chavva <cchavva@marvell.com> >> Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> >> --- >> v2: >> - No change >> - Azure build success here: >> https://dev.azure.com/sr0718/u-boot/_build/results?buildId=59&view=results >> >> .../mach-octeon/include/mach/cvmx-bootinfo.h | 222 --------- >> .../include/mach/cvmx-bootloader.h | 172 +++++++ >> tools/Makefile | 3 + >> tools/update_octeon_header.c | 450 ++++++++++++++++++ >> 4 files changed, 625 insertions(+), 222 deletions(-) >> create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-bootloader.h >> create mode 100644 tools/update_octeon_header.c >> > ... > >> diff --git a/tools/Makefile b/tools/Makefile >> index 51123fd929..253a6b9706 100644 >> --- a/tools/Makefile >> +++ b/tools/Makefile >> @@ -206,6 +206,9 @@ hostprogs-y += proftool >> hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela >> hostprogs-$(CONFIG_RISCV) += prelink-riscv >> >> +hostprogs-$(CONFIG_ARCH_OCTEON) += update_octeon_header >> +update_octeon_header-objs := update_octeon_header.o lib/crc32.o > > entry in tools/.gitignore is missing > >> + >> hostprogs-y += fdtgrep >> fdtgrep-objs += $(LIBFDT_OBJS) common/fdt_region.o fdtgrep.o >> >> diff --git a/tools/update_octeon_header.c b/tools/update_octeon_header.c >> new file mode 100644 >> index 0000000000..964036216d >> --- /dev/null >> +++ b/tools/update_octeon_header.c >> @@ -0,0 +1,450 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Copyright (C) 2020 Marvell International Ltd. >> + */ >> + >> +#include <stdio.h> >> +#include <stdint.h> >> +#include <stddef.h> >> +#include <sys/types.h> >> +#include <sys/stat.h> >> +#include <fcntl.h> >> +#include <unistd.h> >> +#include <stdlib.h> >> +#include <string.h> >> +#include <getopt.h> >> +#include <arpa/inet.h> >> + >> +#include <u-boot/crc.h> >> + >> +#include "mkimage.h" >> + >> +#include "../arch/mips/mach-octeon/include/mach/cvmx-bootloader.h" >> + >> +void usage(void); > > this needs some code cleanup: > - drop the forward declarations and reorder the functions when > necessary > - make all functions static > - drop dead code > - drop debug() macros convert the useful ones to printf > - maybe use fprintf(STDERR, ...) for error messages > > there are also some bugs: > - tool crashes with segfault when called without arguments > - tool crashes when called with a long option but no value > - the bugs above will also be detected by clang-tidy, suggestions for > fixing below Many thanks for the extensive code review. I'll try to address all comments shortly. Thanks, Stefan >> + >> +/* >> + * Do some funky stuff here to get a compile time error if the size of the >> + * bootloader_header structure has changed. >> + */ >> +#define compile_time_assert(cond, msg) char msg[(cond) ? 1 : -1] >> +compile_time_assert(sizeof(struct bootloader_header) == 192, >> + bootloader_header_size_changed); > > there is BUILD_BUG_ON_MSG() in linux/build_bug.h > or compiletime_assert() in linux/compiler.h > >> + >> +#define BUF_SIZE (16 * 1024) >> +#define NAME_LEN 100 >> + >> +#ifndef WOFFSETOF >> +/* word offset */ >> +#define WOFFSETOF(type, elem) (offsetof(type, elem) / 4) >> +#endif >> + >> +#define cvmx_cpu_to_be64(x) (x) >> + >> +static int stage2_flag; >> +static int stage_1_5_flag; >> +static int stage_1_flag; >> + >> +int lookup_board_type(char *board_name) >> +{ >> + int i; >> + int board_type = 0; >> + char *substr = NULL; >> + >> + /* Detect stage 2 bootloader boards */ >> + if (strcasestr(board_name, "_stage2")) { >> + debug("Stage 2 bootloader detected from substring %s in name %s\n", >> + "_stage2", board_name); >> + stage2_flag = 1; >> + } else { >> + debug("Stage 2 bootloader NOT detected from name \"%s\"\n", >> + board_name); >> + } >> + >> + if (strcasestr(board_name, "_stage1")) { >> + debug("Stage 1 bootloader detected from substring %s in name %s\n", >> + "_stage1", board_name); >> + stage_1_flag = 1; >> + } >> + >> + /* Generic is a special case since there are numerous sub-types */ >> + if (!strncasecmp("generic", board_name, strlen("generic"))) >> + return CVMX_BOARD_TYPE_GENERIC; >> + >> + /* >> + * If we're an eMMC stage 2 bootloader, cut off the _emmc_stage2 >> + * part of the name. >> + */ >> + substr = strcasestr(board_name, "_emmc_stage2"); >> + if (substr && (substr[strlen("_emmc_stage2")] == '\0')) { >> + /*return CVMX_BOARD_TYPE_GENERIC;*/ >> + >> + printf(" Converting board name %s to ", board_name); >> + *substr = '\0'; >> + printf("%s\n", board_name); >> + } >> + >> + /* >> + * If we're a NAND stage 2 bootloader, cut off the _nand_stage2 >> + * part of the name. >> + */ >> + substr = strcasestr(board_name, "_nand_stage2"); >> + if (substr && (substr[strlen("_nand_stage2")] == '\0')) { >> + /*return CVMX_BOARD_TYPE_GENERIC;*/ >> + >> + printf(" Converting board name %s to ", board_name); >> + *substr = '\0'; >> + printf("%s\n", board_name); >> + } >> + >> + /* >> + * If we're a SPI stage 2 bootloader, cut off the _spi_stage2 >> + * part of the name. >> + */ >> + substr = strcasestr(board_name, "_spi_stage2"); >> + if (substr && (substr[strlen("_spi_stage2")] == '\0')) { >> + printf(" Converting board name %s to ", board_name); >> + *substr = '\0'; >> + printf("%s\n", board_name); >> + } >> + >> + for (i = CVMX_BOARD_TYPE_NULL; i < CVMX_BOARD_TYPE_MAX; i++) >> + if (!strcasecmp(cvmx_board_type_to_string(i), board_name)) >> + board_type = i; >> + >> + for (i = CVMX_BOARD_TYPE_CUST_DEFINED_MIN; >> + i < CVMX_BOARD_TYPE_CUST_DEFINED_MAX; i++) >> + if (!strncasecmp(cvmx_board_type_to_string(i), board_name, >> + strlen(cvmx_board_type_to_string(i)))) >> + board_type = i; >> + >> + for (i = CVMX_BOARD_TYPE_CUST_PRIVATE_MIN; >> + i < CVMX_BOARD_TYPE_CUST_PRIVATE_MAX; i++) >> + if (!strncasecmp(cvmx_board_type_to_string(i), board_name, >> + strlen(cvmx_board_type_to_string(i)))) >> + board_type = i; >> + >> + return board_type; >> +} >> + >> +/* Getoptions variables must be global */ >> +static int failsafe_flag; >> +static int pciboot_flag; >> +static int env_flag; >> + >> +int main(int argc, char *argv[]) >> +{ >> + int fd; >> + uint8_t buf[BUF_SIZE]; >> + uint32_t data_crc = 0; >> + int len; >> + int data_len = 0; >> + struct bootloader_header header; >> + char filename[NAME_LEN]; >> + int i; >> + int option_index = 0; /* getopt_long stores the option index here. */ >> + char board_name[NAME_LEN] = { 0 }; >> + char tmp_board_name[NAME_LEN] = { 0 }; >> + int c; >> + int board_type = 0; >> + unsigned long long address = 0; >> + ssize_t ret; >> + const char *type_str = NULL; >> + int hdr_size = sizeof(struct bootloader_header); > > the tool has two positional arguments, so you should bail out early. > This will also fix the segfault > > if (argc < 3) { > usage(); > return -1; > } > >> + >> + debug("header size is: %d bytes\n", hdr_size); >> + >> + /* Parse command line options using getopt_long */ >> + while (1) { >> + static struct option long_options[] = { >> + /* These options set a flag. */ >> + {"failsafe", no_argument, &failsafe_flag, 1}, >> + {"pciboot", no_argument, &pciboot_flag, 1}, >> + {"nandstage2", no_argument, &stage2_flag, 1}, >> + {"spistage2", no_argument, &stage2_flag, 1}, >> + {"norstage2", no_argument, &stage2_flag, 1}, >> + {"stage2", no_argument, &stage2_flag, 1}, >> + {"stage1.5", no_argument, &stage_1_5_flag, 1}, >> + {"stage1", no_argument, &stage_1_flag, 1}, >> + {"environment", no_argument, &env_flag, 1}, >> + /* These options don't set a flag. >> + * We distinguish them by their indices. >> + */ >> + {"board", required_argument, 0, 0}, >> + {"text_base", required_argument, 0, 0}, >> + {0, 0, 0, 0} >> + }; > > this should be moved out of main() and marked as static const > >> + >> + c = getopt_long(argc, (char *const *)argv, "h", > > cast is not needed > >> + long_options, &option_index); >> + >> + /* Detect the end of the options. */ >> + if (c == -1) >> + break; >> + >> + switch (c) { >> + /* All long options handled in case 0 */ >> + case 0: >> + /* If this option set a flag, do nothing else now. */ >> + if (long_options[option_index].flag != 0) >> + break; >> + debug("option(l) %s", long_options[option_index].name); >> + if (optarg) >> + debug(" with arg %s", optarg); >> + debug("\n"); > > should be > > if (!optarg) { > usage(); > return -1; > } > debug(" with arg %s\n", optarg); > > the code below depends on optarg and passing a long option without > value is an error and should be notified to the user > >> + >> + if (!strcmp(long_options[option_index].name, "board")) { >> + if (strlen(optarg) >= NAME_LEN) { >> + printf("strncpy() issue detected!"); >> + exit(-1); >> + } >> + strncpy(board_name, optarg, NAME_LEN); >> + >> + debug("Using user supplied board name: %s\n", >> + board_name); >> + } else if (!strcmp(long_options[option_index].name, >> + "text_base")) { >> + address = strtoull(optarg, NULL, 0); >> + debug("Address of image is: 0x%llx\n", >> + (unsigned long long)address); >> + if (!(address & 0xFFFFFFFFULL << 32)) { >> + if (address & 1 << 31) { >> + address |= 0xFFFFFFFFULL << 32; >> + debug("Converting address to 64 bit compatibility space: 0x%llx\n", >> + address); >> + } >> + } >> + } >> + break; >> + >> + case 'h': >> + case '?': >> + /* getopt_long already printed an error message. */ >> + usage(); >> + return -1; >> + >> + default: >> + abort(); >> + } >> + } >> + >> + if (optind < argc) { >> + /* >> + * We only support one argument - an optional bootloader >> + * file name >> + */ >> + if (argc - optind > 2) { >> + debug("non-option ARGV-elements: "); >> + while (optind < argc) >> + debug("%s ", argv[optind++]); >> + debug("\n"); >> + usage(); >> + return -1; >> + } >> + } >> + >> + if (strlen(argv[optind]) >= NAME_LEN) { >> + printf("strncpy() issue detected!"); >> + exit(-1); >> + } >> + strncpy(filename, argv[optind], NAME_LEN); >> + >> + if (board_name[0] == '\0') { >> + if (strlen(argv[optind + 1]) >= NAME_LEN) { >> + printf("strncpy() issue detected!"); >> + exit(-1); >> + } >> + strncpy(board_name, argv[optind + 1], NAME_LEN); >> + } >> + >> + if (strlen(board_name) >= NAME_LEN) { >> + printf("strncpy() issue detected!"); >> + exit(-1); >> + } >> + strncpy(tmp_board_name, board_name, NAME_LEN); >> + >> + fd = open(filename, O_RDWR); >> + if (fd < 0) { >> + printf("Unable to open file: %s\n", filename); >> + exit(-1); >> + } >> + >> + if (failsafe_flag) >> + debug("Setting failsafe flag\n"); >> + >> + if (strlen(board_name)) { >> + int offset = 0; >> + >> + debug("Supplied board name of: %s\n", board_name); >> + >> + if (strstr(board_name, "failsafe")) { >> + failsafe_flag = 1; >> + debug("Setting failsafe flag based on board name\n"); >> + } >> + /* Skip leading octeon_ if present. */ >> + if (!strncmp(board_name, "octeon_", 7)) >> + offset = 7; >> + >> + /* >> + * Check to see if 'failsafe' is in the name. If so, set the >> + * failsafe flag. Also, ignore extra trailing characters on >> + * passed parameter when comparing against board names. >> + * We actually use the configuration name from u-boot, so it >> + * may have some other variant names. Variants other than >> + * failsafe _must_ be passed to this program explicitly >> + */ >> + >> + board_type = lookup_board_type(board_name + offset); >> + if (!board_type) { >> + /* Retry with 'cust_' prefix to catch boards that are >> + * in the customer section (such as nb5) >> + */ >> + sprintf(tmp_board_name, "cust_%s", board_name + offset); >> + board_type = lookup_board_type(tmp_board_name); >> + } >> + >> + /* reset to original value */ >> + strncpy(tmp_board_name, board_name, NAME_LEN); >> + if (!board_type) { >> + /* >> + * Retry with 'cust_private_' prefix to catch boards >> + * that are in the customer private section >> + */ >> + sprintf(tmp_board_name, "cust_private_%s", >> + board_name + offset); >> + board_type = lookup_board_type(tmp_board_name); >> + } >> + >> + if (!board_type) { >> + printf("ERROR: unable to determine board type\n"); >> + exit(-1); >> + } >> + debug("Board type is: %d: %s\n", board_type, >> + cvmx_board_type_to_string(board_type)); >> + } else { >> + printf("Board name must be specified!\n"); >> + exit(-1); >> + } >> + >> + /* >> + * Check to see if there is either an existing header, or that there >> + * are zero valued bytes where we want to put the header >> + */ >> + len = read(fd, buf, BUF_SIZE); >> + if (len > 0) { >> + /* >> + * Copy the header, as the first word (jump instruction, needs >> + * to remain the same. >> + */ >> + memcpy(&header, buf, hdr_size); >> + /* >> + * Check to see if we have zero bytes (excluding first 4, which >> + * are the jump instruction) >> + */ >> + for (i = 1; i < hdr_size / 4; i++) { >> + if (((uint32_t *)buf)[i]) { >> + printf("ERROR: non-zero word found %x in location %d required for header, aborting\n", >> + ((uint32_t *)buf)[i], i); >> + exit(-1); >> + } >> + } >> + debug("Zero bytes found in header location, adding header.\n"); >> + >> + } else { >> + printf("Unable to read from file %s\n", filename); >> + exit(-1); >> + } >> + >> + /* Read data bytes and generate CRC */ >> + lseek(fd, hdr_size, SEEK_SET); >> + >> + while ((len = read(fd, buf, BUF_SIZE)) > 0) { >> + data_crc = crc32(data_crc, buf, len); >> + data_len += len; >> + } >> + printf("CRC of data: 0x%x, length: %d\n", data_crc, data_len); >> + >> + /* Now create the new header */ >> + header.magic = htonl(BOOTLOADER_HEADER_MAGIC); >> + header.maj_rev = htons(BOOTLOADER_HEADER_CURRENT_MAJOR_REV); >> + header.min_rev = htons(BOOTLOADER_HEADER_CURRENT_MINOR_REV); >> + header.dlen = htonl(data_len); >> + header.dcrc = htonl(data_crc); >> + header.board_type = htons(board_type); >> + header.address = cvmx_cpu_to_be64(address); > > cvmx_cpu_to_be64() is a no-op, is this intentional? If yes, this macro > can be removed. Otherwise you can use cpu_to_be64(). All cpu_to_be*() > functions are automatically available in tools/ directory. > > Viele Grüße, Stefan
diff --git a/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h b/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h index 337987178f..97438ff787 100644 --- a/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h +++ b/arch/mips/mach-octeon/include/mach/cvmx-bootinfo.h @@ -125,226 +125,4 @@ struct cvmx_bootinfo { #endif /* (CVMX_BOOTINFO_MAJ_VER == 1) */ -/* Type defines for board and chip types */ -enum cvmx_board_types_enum { - CVMX_BOARD_TYPE_NULL = 0, - CVMX_BOARD_TYPE_SIM = 1, - CVMX_BOARD_TYPE_EBT3000 = 2, - CVMX_BOARD_TYPE_KODAMA = 3, - CVMX_BOARD_TYPE_NIAGARA = 4, - CVMX_BOARD_TYPE_NAC38 = 5, /* formerly NAO38 */ - CVMX_BOARD_TYPE_THUNDER = 6, - CVMX_BOARD_TYPE_TRANTOR = 7, - CVMX_BOARD_TYPE_EBH3000 = 8, - CVMX_BOARD_TYPE_EBH3100 = 9, - CVMX_BOARD_TYPE_HIKARI = 10, - CVMX_BOARD_TYPE_CN3010_EVB_HS5 = 11, - CVMX_BOARD_TYPE_CN3005_EVB_HS5 = 12, - CVMX_BOARD_TYPE_KBP = 13, - /* Deprecated, CVMX_BOARD_TYPE_CN3010_EVB_HS5 supports the CN3020 */ - CVMX_BOARD_TYPE_CN3020_EVB_HS5 = 14, - CVMX_BOARD_TYPE_EBT5800 = 15, - CVMX_BOARD_TYPE_NICPRO2 = 16, - CVMX_BOARD_TYPE_EBH5600 = 17, - CVMX_BOARD_TYPE_EBH5601 = 18, - CVMX_BOARD_TYPE_EBH5200 = 19, - CVMX_BOARD_TYPE_BBGW_REF = 20, - CVMX_BOARD_TYPE_NIC_XLE_4G = 21, - CVMX_BOARD_TYPE_EBT5600 = 22, - CVMX_BOARD_TYPE_EBH5201 = 23, - CVMX_BOARD_TYPE_EBT5200 = 24, - CVMX_BOARD_TYPE_CB5600 = 25, - CVMX_BOARD_TYPE_CB5601 = 26, - CVMX_BOARD_TYPE_CB5200 = 27, - /* Special 'generic' board type, supports many boards */ - CVMX_BOARD_TYPE_GENERIC = 28, - CVMX_BOARD_TYPE_EBH5610 = 29, - CVMX_BOARD_TYPE_LANAI2_A = 30, - CVMX_BOARD_TYPE_LANAI2_U = 31, - CVMX_BOARD_TYPE_EBB5600 = 32, - CVMX_BOARD_TYPE_EBB6300 = 33, - CVMX_BOARD_TYPE_NIC_XLE_10G = 34, - CVMX_BOARD_TYPE_LANAI2_G = 35, - CVMX_BOARD_TYPE_EBT5810 = 36, - CVMX_BOARD_TYPE_NIC10E = 37, - CVMX_BOARD_TYPE_EP6300C = 38, - CVMX_BOARD_TYPE_EBB6800 = 39, - CVMX_BOARD_TYPE_NIC4E = 40, - CVMX_BOARD_TYPE_NIC2E = 41, - CVMX_BOARD_TYPE_EBB6600 = 42, - CVMX_BOARD_TYPE_REDWING = 43, - CVMX_BOARD_TYPE_NIC68_4 = 44, - CVMX_BOARD_TYPE_NIC10E_66 = 45, - CVMX_BOARD_TYPE_MAX, - - /* - * The range from CVMX_BOARD_TYPE_MAX to - * CVMX_BOARD_TYPE_CUST_DEFINED_MIN is reserved for future - * SDK use. - */ - - /* - * Set aside a range for customer boards. These numbers are managed - * by Cavium. - */ - CVMX_BOARD_TYPE_CUST_DEFINED_MIN = 10000, - CVMX_BOARD_TYPE_CUST_WSX16 = 10001, - CVMX_BOARD_TYPE_CUST_NS0216 = 10002, - CVMX_BOARD_TYPE_CUST_NB5 = 10003, - CVMX_BOARD_TYPE_CUST_WMR500 = 10004, - CVMX_BOARD_TYPE_CUST_ITB101 = 10005, - CVMX_BOARD_TYPE_CUST_NTE102 = 10006, - CVMX_BOARD_TYPE_CUST_AGS103 = 10007, - CVMX_BOARD_TYPE_CUST_GST104 = 10008, - CVMX_BOARD_TYPE_CUST_GCT105 = 10009, - CVMX_BOARD_TYPE_CUST_AGS106 = 10010, - CVMX_BOARD_TYPE_CUST_SGM107 = 10011, - CVMX_BOARD_TYPE_CUST_GCT108 = 10012, - CVMX_BOARD_TYPE_CUST_AGS109 = 10013, - CVMX_BOARD_TYPE_CUST_GCT110 = 10014, - CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER = 10015, - CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER = 10016, - CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX = 10017, - CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX = 10018, - CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX = 10019, - CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX = 10020, - CVMX_BOARD_TYPE_CUST_L2_ZINWELL = 10021, - CVMX_BOARD_TYPE_CUST_DEFINED_MAX = 20000, - - /* - * Set aside a range for customer private use. The SDK won't - * use any numbers in this range. - */ - CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, - CVMX_BOARD_TYPE_UBNT_E100 = 20002, - CVMX_BOARD_TYPE_CUST_DSR1000N = 20006, - CVMX_BOARD_TYPE_KONTRON_S1901 = 21901, - CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, - - /* The remaining range is reserved for future use. */ -}; - -enum cvmx_chip_types_enum { - CVMX_CHIP_TYPE_NULL = 0, - CVMX_CHIP_SIM_TYPE_DEPRECATED = 1, - CVMX_CHIP_TYPE_OCTEON_SAMPLE = 2, - CVMX_CHIP_TYPE_MAX, -}; - -/* - * Compatibility alias for NAC38 name change, planned to be removed - * from SDK 1.7 - */ -#define CVMX_BOARD_TYPE_NAO38 CVMX_BOARD_TYPE_NAC38 - -/* Functions to return string based on type */ -#define ENUM_BRD_TYPE_CASE(x) \ - case x: \ - return(#x + 16) /* Skip CVMX_BOARD_TYPE_ */ - -static inline const char *cvmx_board_type_to_string(enum - cvmx_board_types_enum type) -{ - switch (type) { - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NULL); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_SIM); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT3000); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KODAMA); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIAGARA); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NAC38); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_THUNDER); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_TRANTOR); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH3000); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH3100); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_HIKARI); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3010_EVB_HS5); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3005_EVB_HS5); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KBP); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CN3020_EVB_HS5); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5800); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NICPRO2); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5601); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5200); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_BBGW_REF); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC_XLE_4G); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5201); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5200); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5601); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CB5200); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_GENERIC); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBH5610); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_A); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_U); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB5600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6300); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC_XLE_10G); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_LANAI2_G); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBT5810); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EP6300C); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6800); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC4E); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC2E); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB6600); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_REDWING); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC68_4); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NIC10E_66); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX); - - /* Customer boards listed here */ - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MIN); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WSX16); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NS0216); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NB5); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_WMR500); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_ITB101); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_NTE102); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS103); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GST104); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT105); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS106); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_SGM107); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT108); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_AGS109); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_GCT110); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_SENDER); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_AIR_RECEIVER); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_TX); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ACCTON2_RX); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_TX); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_WSTRNSNIC_RX); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_L2_ZINWELL); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MAX); - - /* Customer private range */ - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DSR1000N); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901); - ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX); - } - - return NULL; -} - -#define ENUM_CHIP_TYPE_CASE(x) \ - case x: \ - return(#x + 15) /* Skip CVMX_CHIP_TYPE */ - -static inline const char *cvmx_chip_type_to_string(enum - cvmx_chip_types_enum type) -{ - switch (type) { - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_NULL); - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_SIM_TYPE_DEPRECATED); - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_OCTEON_SAMPLE); - ENUM_CHIP_TYPE_CASE(CVMX_CHIP_TYPE_MAX); - } - - return "Unsupported Chip"; -} - #endif /* __CVMX_BOOTINFO_H__ */ diff --git a/arch/mips/mach-octeon/include/mach/cvmx-bootloader.h b/arch/mips/mach-octeon/include/mach/cvmx-bootloader.h new file mode 100644 index 0000000000..9abe021452 --- /dev/null +++ b/arch/mips/mach-octeon/include/mach/cvmx-bootloader.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +/* + * Bootloader definitions that are shared with other programs + */ + +#ifndef __CVMX_BOOTLOADER__ +#define __CVMX_BOOTLOADER__ + +/* + * The bootloader_header_t structure defines the header that is present + * at the start of binary u-boot images. This header is used to locate + * the bootloader image in NAND, and also to allow verification of images + * for normal NOR booting. This structure is placed at the beginning of a + * bootloader binary image, and remains in the executable code. + */ +#define BOOTLOADER_HEADER_MAGIC 0x424f4f54 /* "BOOT" in ASCII */ + +#define BOOTLOADER_HEADER_COMMENT_LEN 64 +#define BOOTLOADER_HEADER_VERSION_LEN 64 +/* limited by the space to the next exception handler */ +#define BOOTLOADER_HEADER_MAX_SIZE 0x200 + +#define BOOTLOADER_HEADER_CURRENT_MAJOR_REV 1 +#define BOOTLOADER_HEADER_CURRENT_MINOR_REV 2 +/* + * Revision history + * 1.1 Initial released revision. (SDK 1.9) + * 1.2 TLB based relocatable image (SDK 2.0) + */ + +#ifndef __ASSEMBLY__ +struct bootloader_header { + uint32_t jump_instr; /* + * Jump to executable code following the + * header. This allows this header to be + * (and remain) part of the executable image) + */ + uint32_t nop_instr; /* Must be 0x0 */ + uint32_t magic; /* Magic number to identify header */ + uint32_t hcrc; /* CRC of all of header excluding this field */ + + uint16_t hlen; /* Length of header in bytes */ + uint16_t maj_rev; /* Major revision */ + uint16_t min_rev; /* Minor revision */ + uint16_t board_type; /* Board type that the image is for */ + + uint32_t dlen; /* Length of data (following header) in bytes */ + uint32_t dcrc; /* CRC of data */ + uint64_t address; /* Mips virtual address */ + uint32_t flags; + uint16_t image_type; /* Defined in bootloader_image_t enum */ + uint16_t resv0; /* pad */ + + uint32_t reserved1; + uint32_t reserved2; + uint32_t reserved3; + uint32_t reserved4; + + /* Optional, for descriptive purposes */ + char comment_string[BOOTLOADER_HEADER_COMMENT_LEN]; + /* Optional, for descriptive purposes */ + char version_string[BOOTLOADER_HEADER_VERSION_LEN]; +} __packed; + +/* Defines for flag field */ +#define BL_HEADER_FLAG_FAILSAFE 1 + +enum bootloader_image { + BL_HEADER_IMAGE_UNKNOWN = 0x0, + BL_HEADER_IMAGE_STAGE2, /* Binary bootloader stage2 image */ + BL_HEADER_IMAGE_STAGE3, /* Binary bootloader stage3 image */ + BL_HEADER_IMAGE_NOR, /* Binary bootloader for NOR boot */ + BL_HEADER_IMAGE_PCIBOOT, /* Binary bootloader for PCI boot */ + BL_HEADER_IMAGE_UBOOT_ENV, /* Environment for u-boot */ + /* Bootloader before U-Boot (stage 1/1.5) */ + BL_HEADER_IMAGE_PRE_UBOOT, + BL_HEADER_IMAGE_STAGE1, /* NOR stage 1 bootloader */ + BL_HEADER_IMAGE_MAX, + /* Range for customer private use. Will not be used by Cavium Inc. */ + BL_HEADER_IMAGE_CUST_RESERVED_MIN = 0x1000, + BL_HEADER_IMAGE_CUST_RESERVED_MAX = 0x1fff +}; + +#endif /* __ASSEMBLY__ */ + +/* + * Maximum address searched for NAND boot images and environments. + * This is used by stage1 and stage2. + */ +#define MAX_NAND_SEARCH_ADDR 0x800000 + +/* Maximum address to look for start of normal bootloader */ +#define MAX_NOR_SEARCH_ADDR 0x400000 + +/* + * Defines for RAM based environment set by the host or the previous + * bootloader in a chain boot configuration. + */ + +#define U_BOOT_RAM_ENV_ADDR 0x1000 +#define U_BOOT_RAM_ENV_SIZE 0x1000 +#define U_BOOT_RAM_ENV_CRC_SIZE 0x4 +#define U_BOOT_RAM_ENV_ADDR_2 (U_BOOT_RAM_ENV_ADDR + U_BOOT_RAM_ENV_SIZE) +/* Address of environment in L2 cache if booted from cache */ +#define U_BOOT_CACHE_ENV_ADDR 0x000ff000 +/* Size of environment in L2 cache */ +#define U_BOOT_CACHE_ENV_SIZE 0x1000 + +/* Board numbers and names */ + +/* Type defines for board and chip types */ +enum cvmx_board_types_enum { + CVMX_BOARD_TYPE_NULL = 0, + CVMX_BOARD_TYPE_SIM = 1, + /* Special 'generic' board type, supports many boards */ + CVMX_BOARD_TYPE_GENERIC = 28, + CVMX_BOARD_TYPE_EBB7304 = 76, + CVMX_BOARD_TYPE_MAX, + /* NOTE: 256-257 are being used by a customer. */ + + /* + * The range from CVMX_BOARD_TYPE_MAX to + * CVMX_BOARD_TYPE_CUST_DEFINED_MIN is reserved + * for future SDK use. + */ + + /* + * Set aside a range for customer boards. These numbers are managed + * by Cavium. + */ + CVMX_BOARD_TYPE_CUST_DEFINED_MIN = 10000, + CVMX_BOARD_TYPE_CUST_DEFINED_MAX = 20000, + + /* + * Set aside a range for customer private use. The SDK won't + * use any numbers in this range. + */ + CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, + CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, +}; + +/* Functions to return string based on type */ +/* Skip CVMX_BOARD_TYPE_ */ +#define ENUM_BRD_TYPE_CASE(x) case x: return(#x + 16) + +static inline const char +*cvmx_board_type_to_string(enum cvmx_board_types_enum type) +{ + switch (type) { + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_NULL); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_SIM); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_GENERIC); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_EBB7304); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_MAX); + + /* Customer boards listed here */ + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MIN); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DEFINED_MAX); + + /* Customer private range */ + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN); + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX); + } + + return "Unsupported Board"; +} + +#endif /* __CVMX_BOOTLOADER__ */ diff --git a/tools/Makefile b/tools/Makefile index 51123fd929..253a6b9706 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -206,6 +206,9 @@ hostprogs-y += proftool hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela hostprogs-$(CONFIG_RISCV) += prelink-riscv +hostprogs-$(CONFIG_ARCH_OCTEON) += update_octeon_header +update_octeon_header-objs := update_octeon_header.o lib/crc32.o + hostprogs-y += fdtgrep fdtgrep-objs += $(LIBFDT_OBJS) common/fdt_region.o fdtgrep.o diff --git a/tools/update_octeon_header.c b/tools/update_octeon_header.c new file mode 100644 index 0000000000..964036216d --- /dev/null +++ b/tools/update_octeon_header.c @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Marvell International Ltd. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <arpa/inet.h> + +#include <u-boot/crc.h> + +#include "mkimage.h" + +#include "../arch/mips/mach-octeon/include/mach/cvmx-bootloader.h" + +void usage(void); + +/* + * Do some funky stuff here to get a compile time error if the size of the + * bootloader_header structure has changed. + */ +#define compile_time_assert(cond, msg) char msg[(cond) ? 1 : -1] +compile_time_assert(sizeof(struct bootloader_header) == 192, + bootloader_header_size_changed); + +#define BUF_SIZE (16 * 1024) +#define NAME_LEN 100 + +#ifndef WOFFSETOF +/* word offset */ +#define WOFFSETOF(type, elem) (offsetof(type, elem) / 4) +#endif + +#define cvmx_cpu_to_be64(x) (x) + +static int stage2_flag; +static int stage_1_5_flag; +static int stage_1_flag; + +int lookup_board_type(char *board_name) +{ + int i; + int board_type = 0; + char *substr = NULL; + + /* Detect stage 2 bootloader boards */ + if (strcasestr(board_name, "_stage2")) { + debug("Stage 2 bootloader detected from substring %s in name %s\n", + "_stage2", board_name); + stage2_flag = 1; + } else { + debug("Stage 2 bootloader NOT detected from name \"%s\"\n", + board_name); + } + + if (strcasestr(board_name, "_stage1")) { + debug("Stage 1 bootloader detected from substring %s in name %s\n", + "_stage1", board_name); + stage_1_flag = 1; + } + + /* Generic is a special case since there are numerous sub-types */ + if (!strncasecmp("generic", board_name, strlen("generic"))) + return CVMX_BOARD_TYPE_GENERIC; + + /* + * If we're an eMMC stage 2 bootloader, cut off the _emmc_stage2 + * part of the name. + */ + substr = strcasestr(board_name, "_emmc_stage2"); + if (substr && (substr[strlen("_emmc_stage2")] == '\0')) { + /*return CVMX_BOARD_TYPE_GENERIC;*/ + + printf(" Converting board name %s to ", board_name); + *substr = '\0'; + printf("%s\n", board_name); + } + + /* + * If we're a NAND stage 2 bootloader, cut off the _nand_stage2 + * part of the name. + */ + substr = strcasestr(board_name, "_nand_stage2"); + if (substr && (substr[strlen("_nand_stage2")] == '\0')) { + /*return CVMX_BOARD_TYPE_GENERIC;*/ + + printf(" Converting board name %s to ", board_name); + *substr = '\0'; + printf("%s\n", board_name); + } + + /* + * If we're a SPI stage 2 bootloader, cut off the _spi_stage2 + * part of the name. + */ + substr = strcasestr(board_name, "_spi_stage2"); + if (substr && (substr[strlen("_spi_stage2")] == '\0')) { + printf(" Converting board name %s to ", board_name); + *substr = '\0'; + printf("%s\n", board_name); + } + + for (i = CVMX_BOARD_TYPE_NULL; i < CVMX_BOARD_TYPE_MAX; i++) + if (!strcasecmp(cvmx_board_type_to_string(i), board_name)) + board_type = i; + + for (i = CVMX_BOARD_TYPE_CUST_DEFINED_MIN; + i < CVMX_BOARD_TYPE_CUST_DEFINED_MAX; i++) + if (!strncasecmp(cvmx_board_type_to_string(i), board_name, + strlen(cvmx_board_type_to_string(i)))) + board_type = i; + + for (i = CVMX_BOARD_TYPE_CUST_PRIVATE_MIN; + i < CVMX_BOARD_TYPE_CUST_PRIVATE_MAX; i++) + if (!strncasecmp(cvmx_board_type_to_string(i), board_name, + strlen(cvmx_board_type_to_string(i)))) + board_type = i; + + return board_type; +} + +/* Getoptions variables must be global */ +static int failsafe_flag; +static int pciboot_flag; +static int env_flag; + +int main(int argc, char *argv[]) +{ + int fd; + uint8_t buf[BUF_SIZE]; + uint32_t data_crc = 0; + int len; + int data_len = 0; + struct bootloader_header header; + char filename[NAME_LEN]; + int i; + int option_index = 0; /* getopt_long stores the option index here. */ + char board_name[NAME_LEN] = { 0 }; + char tmp_board_name[NAME_LEN] = { 0 }; + int c; + int board_type = 0; + unsigned long long address = 0; + ssize_t ret; + const char *type_str = NULL; + int hdr_size = sizeof(struct bootloader_header); + + debug("header size is: %d bytes\n", hdr_size); + + /* Parse command line options using getopt_long */ + while (1) { + static struct option long_options[] = { + /* These options set a flag. */ + {"failsafe", no_argument, &failsafe_flag, 1}, + {"pciboot", no_argument, &pciboot_flag, 1}, + {"nandstage2", no_argument, &stage2_flag, 1}, + {"spistage2", no_argument, &stage2_flag, 1}, + {"norstage2", no_argument, &stage2_flag, 1}, + {"stage2", no_argument, &stage2_flag, 1}, + {"stage1.5", no_argument, &stage_1_5_flag, 1}, + {"stage1", no_argument, &stage_1_flag, 1}, + {"environment", no_argument, &env_flag, 1}, + /* These options don't set a flag. + * We distinguish them by their indices. + */ + {"board", required_argument, 0, 0}, + {"text_base", required_argument, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long(argc, (char *const *)argv, "h", + long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) + break; + + switch (c) { + /* All long options handled in case 0 */ + case 0: + /* If this option set a flag, do nothing else now. */ + if (long_options[option_index].flag != 0) + break; + debug("option(l) %s", long_options[option_index].name); + if (optarg) + debug(" with arg %s", optarg); + debug("\n"); + + if (!strcmp(long_options[option_index].name, "board")) { + if (strlen(optarg) >= NAME_LEN) { + printf("strncpy() issue detected!"); + exit(-1); + } + strncpy(board_name, optarg, NAME_LEN); + + debug("Using user supplied board name: %s\n", + board_name); + } else if (!strcmp(long_options[option_index].name, + "text_base")) { + address = strtoull(optarg, NULL, 0); + debug("Address of image is: 0x%llx\n", + (unsigned long long)address); + if (!(address & 0xFFFFFFFFULL << 32)) { + if (address & 1 << 31) { + address |= 0xFFFFFFFFULL << 32; + debug("Converting address to 64 bit compatibility space: 0x%llx\n", + address); + } + } + } + break; + + case 'h': + case '?': + /* getopt_long already printed an error message. */ + usage(); + return -1; + + default: + abort(); + } + } + + if (optind < argc) { + /* + * We only support one argument - an optional bootloader + * file name + */ + if (argc - optind > 2) { + debug("non-option ARGV-elements: "); + while (optind < argc) + debug("%s ", argv[optind++]); + debug("\n"); + usage(); + return -1; + } + } + + if (strlen(argv[optind]) >= NAME_LEN) { + printf("strncpy() issue detected!"); + exit(-1); + } + strncpy(filename, argv[optind], NAME_LEN); + + if (board_name[0] == '\0') { + if (strlen(argv[optind + 1]) >= NAME_LEN) { + printf("strncpy() issue detected!"); + exit(-1); + } + strncpy(board_name, argv[optind + 1], NAME_LEN); + } + + if (strlen(board_name) >= NAME_LEN) { + printf("strncpy() issue detected!"); + exit(-1); + } + strncpy(tmp_board_name, board_name, NAME_LEN); + + fd = open(filename, O_RDWR); + if (fd < 0) { + printf("Unable to open file: %s\n", filename); + exit(-1); + } + + if (failsafe_flag) + debug("Setting failsafe flag\n"); + + if (strlen(board_name)) { + int offset = 0; + + debug("Supplied board name of: %s\n", board_name); + + if (strstr(board_name, "failsafe")) { + failsafe_flag = 1; + debug("Setting failsafe flag based on board name\n"); + } + /* Skip leading octeon_ if present. */ + if (!strncmp(board_name, "octeon_", 7)) + offset = 7; + + /* + * Check to see if 'failsafe' is in the name. If so, set the + * failsafe flag. Also, ignore extra trailing characters on + * passed parameter when comparing against board names. + * We actually use the configuration name from u-boot, so it + * may have some other variant names. Variants other than + * failsafe _must_ be passed to this program explicitly + */ + + board_type = lookup_board_type(board_name + offset); + if (!board_type) { + /* Retry with 'cust_' prefix to catch boards that are + * in the customer section (such as nb5) + */ + sprintf(tmp_board_name, "cust_%s", board_name + offset); + board_type = lookup_board_type(tmp_board_name); + } + + /* reset to original value */ + strncpy(tmp_board_name, board_name, NAME_LEN); + if (!board_type) { + /* + * Retry with 'cust_private_' prefix to catch boards + * that are in the customer private section + */ + sprintf(tmp_board_name, "cust_private_%s", + board_name + offset); + board_type = lookup_board_type(tmp_board_name); + } + + if (!board_type) { + printf("ERROR: unable to determine board type\n"); + exit(-1); + } + debug("Board type is: %d: %s\n", board_type, + cvmx_board_type_to_string(board_type)); + } else { + printf("Board name must be specified!\n"); + exit(-1); + } + + /* + * Check to see if there is either an existing header, or that there + * are zero valued bytes where we want to put the header + */ + len = read(fd, buf, BUF_SIZE); + if (len > 0) { + /* + * Copy the header, as the first word (jump instruction, needs + * to remain the same. + */ + memcpy(&header, buf, hdr_size); + /* + * Check to see if we have zero bytes (excluding first 4, which + * are the jump instruction) + */ + for (i = 1; i < hdr_size / 4; i++) { + if (((uint32_t *)buf)[i]) { + printf("ERROR: non-zero word found %x in location %d required for header, aborting\n", + ((uint32_t *)buf)[i], i); + exit(-1); + } + } + debug("Zero bytes found in header location, adding header.\n"); + + } else { + printf("Unable to read from file %s\n", filename); + exit(-1); + } + + /* Read data bytes and generate CRC */ + lseek(fd, hdr_size, SEEK_SET); + + while ((len = read(fd, buf, BUF_SIZE)) > 0) { + data_crc = crc32(data_crc, buf, len); + data_len += len; + } + printf("CRC of data: 0x%x, length: %d\n", data_crc, data_len); + + /* Now create the new header */ + header.magic = htonl(BOOTLOADER_HEADER_MAGIC); + header.maj_rev = htons(BOOTLOADER_HEADER_CURRENT_MAJOR_REV); + header.min_rev = htons(BOOTLOADER_HEADER_CURRENT_MINOR_REV); + header.dlen = htonl(data_len); + header.dcrc = htonl(data_crc); + header.board_type = htons(board_type); + header.address = cvmx_cpu_to_be64(address); + if (failsafe_flag) + header.flags |= htonl(BL_HEADER_FLAG_FAILSAFE); + + debug("Stage 2 flag is %sset\n", stage2_flag ? "" : "not "); + debug("Stage 1 flag is %sset\n", stage_1_flag ? "" : "not "); + if (pciboot_flag) + header.image_type = htons(BL_HEADER_IMAGE_PCIBOOT); + else if (stage2_flag) + header.image_type = htons(BL_HEADER_IMAGE_STAGE2); + else if (stage_1_flag) + header.image_type = htons(BL_HEADER_IMAGE_STAGE1); + else if (env_flag) + header.image_type = htons(BL_HEADER_IMAGE_UBOOT_ENV); + else if (stage_1_5_flag || stage_1_flag) + header.image_type = htons(BL_HEADER_IMAGE_PRE_UBOOT); + else + header.image_type = htons(BL_HEADER_IMAGE_NOR); + + switch (ntohs(header.image_type)) { + case BL_HEADER_IMAGE_UNKNOWN: + type_str = "Unknown"; + break; + case BL_HEADER_IMAGE_STAGE1: + type_str = "Stage 1"; + break; + case BL_HEADER_IMAGE_STAGE2: + type_str = "Stage 2"; + break; + case BL_HEADER_IMAGE_PRE_UBOOT: + type_str = "Pre-U-Boot"; + break; + case BL_HEADER_IMAGE_STAGE3: + type_str = "Stage 3"; + break; + case BL_HEADER_IMAGE_NOR: + type_str = "NOR"; + break; + case BL_HEADER_IMAGE_PCIBOOT: + type_str = "PCI Boot"; + break; + case BL_HEADER_IMAGE_UBOOT_ENV: + type_str = "U-Boot Environment"; + break; + default: + if (ntohs(header.image_type) >= BL_HEADER_IMAGE_CUST_RESERVED_MIN && + ntohs(header.image_type) <= BL_HEADER_IMAGE_CUST_RESERVED_MAX) + type_str = "Customer Reserved"; + else + type_str = "Unsupported"; + } + printf("Header image type: %s\n", type_str); + header.hlen = htons(hdr_size); + + /* Now compute header CRC over all of the header excluding the CRC */ + header.hcrc = crc32(0, (void *)&header, 12); + header.hcrc = htonl(crc32(header.hcrc, ((void *)&(header)) + 16, + hdr_size - 16)); + + /* Seek to beginning of file */ + lseek(fd, 0, SEEK_SET); + + /* Write header to file */ + ret = write(fd, &header, hdr_size); + if (ret < 0) + perror("write"); + + close(fd); + + printf("Header CRC: 0x%x\n", ntohl(header.hcrc)); + return 0; +} + +void usage(void) +{ + printf("Usage: update_octeon_header <filename> <board_name> [--failsafe] [--text_base=0xXXXXX]\n"); +}
Add a tool to update or insert an Octeon specific header into the U-Boot image. This is needed e.g. for booting via SPI NOR, eMMC and NAND. While working on this, move enum cvmx_board_types_enum and cvmx_board_type_to_string() to cvmx-bootloader.h and remove the unreferenced (unsupported) board definition. Signed-off-by: Stefan Roese <sr@denx.de> Cc: Aaron Williams <awilliams@marvell.com> Cc: Chandrakala Chavva <cchavva@marvell.com> Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com> --- v2: - No change - Azure build success here: https://dev.azure.com/sr0718/u-boot/_build/results?buildId=59&view=results .../mach-octeon/include/mach/cvmx-bootinfo.h | 222 --------- .../include/mach/cvmx-bootloader.h | 172 +++++++ tools/Makefile | 3 + tools/update_octeon_header.c | 450 ++++++++++++++++++ 4 files changed, 625 insertions(+), 222 deletions(-) create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-bootloader.h create mode 100644 tools/update_octeon_header.c