diff options
Diffstat (limited to 'roms/u-boot/board/esd/common/auto_update.c')
-rw-r--r-- | roms/u-boot/board/esd/common/auto_update.c | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/roms/u-boot/board/esd/common/auto_update.c b/roms/u-boot/board/esd/common/auto_update.c new file mode 100644 index 00000000..85c3567b --- /dev/null +++ b/roms/u-boot/board/esd/common/auto_update.c @@ -0,0 +1,484 @@ +/* + * (C) Copyright 2003-2004 + * Gary Jennejohn, DENX Software Engineering, garyj@denx.de. + * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#include <command.h> +#include <image.h> +#include <asm/byteorder.h> +#include <fat.h> +#include <part.h> + +#include "auto_update.h" + +#ifdef CONFIG_AUTO_UPDATE + +#if !defined(CONFIG_CMD_FAT) +#error "must define CONFIG_CMD_FAT" +#endif + +extern au_image_t au_image[]; +extern int N_AU_IMAGES; + +/* where to load files into memory */ +#define LOAD_ADDR ((unsigned char *)0x100000) +#define MAX_LOADSZ 0x1c00000 + +/* externals */ +extern int fat_register_device(block_dev_desc_t *, int); +extern int file_fat_detectfs(void); +extern long file_fat_read(const char *, void *, unsigned long); +long do_fat_read (const char *filename, void *buffer, + unsigned long maxsize, int dols); +extern int flash_sect_erase(ulong, ulong); +extern int flash_sect_protect (int, ulong, ulong); +extern int flash_write (char *, ulong, ulong); + +extern block_dev_desc_t ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE]; + +int au_check_cksum_valid(int i, long nbytes) +{ + image_header_t *hdr; + + hdr = (image_header_t *)LOAD_ADDR; +#if defined(CONFIG_FIT) + if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) { + puts ("Non legacy image format not supported\n"); + return -1; + } +#endif + + if ((au_image[i].type == AU_FIRMWARE) && + (au_image[i].size != image_get_data_size (hdr))) { + printf ("Image %s has wrong size\n", au_image[i].name); + return -1; + } + + if (nbytes != (image_get_image_size (hdr))) { + printf ("Image %s bad total SIZE\n", au_image[i].name); + return -1; + } + + /* check the data CRC */ + if (!image_check_dcrc (hdr)) { + printf ("Image %s bad data checksum\n", au_image[i].name); + return -1; + } + return 0; +} + +int au_check_header_valid(int i, long nbytes) +{ + image_header_t *hdr; + + hdr = (image_header_t *)LOAD_ADDR; +#if defined(CONFIG_FIT) + if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) { + puts ("Non legacy image format not supported\n"); + return -1; + } +#endif + + /* check the easy ones first */ + if (nbytes < image_get_header_size ()) { + printf ("Image %s bad header SIZE\n", au_image[i].name); + return -1; + } + if (!image_check_magic (hdr) || !image_check_arch (hdr, IH_ARCH_PPC)) { + printf ("Image %s bad MAGIC or ARCH\n", au_image[i].name); + return -1; + } + if (!image_check_hcrc (hdr)) { + printf ("Image %s bad header checksum\n", au_image[i].name); + return -1; + } + + /* check the type - could do this all in one gigantic if() */ + if (((au_image[i].type & AU_TYPEMASK) == AU_FIRMWARE) && + !image_check_type (hdr, IH_TYPE_FIRMWARE)) { + printf ("Image %s wrong type\n", au_image[i].name); + return -1; + } + if (((au_image[i].type & AU_TYPEMASK) == AU_SCRIPT) && + !image_check_type (hdr, IH_TYPE_SCRIPT)) { + printf ("Image %s wrong type\n", au_image[i].name); + return -1; + } + + return 0; +} + +int au_do_update(int i, long sz) +{ + image_header_t *hdr; + char *addr; + long start, end; + int off, rc; + uint nbytes; + int k; + + hdr = (image_header_t *)LOAD_ADDR; +#if defined(CONFIG_FIT) + if (genimg_get_format ((void *)hdr) != IMAGE_FORMAT_LEGACY) { + puts ("Non legacy image format not supported\n"); + return -1; + } +#endif + + switch (au_image[i].type & AU_TYPEMASK) { + case AU_SCRIPT: + printf("Executing script %s\n", au_image[i].name); + + /* execute a script */ + if (image_check_type (hdr, IH_TYPE_SCRIPT)) { + addr = (char *)((char *)hdr + image_get_header_size ()); + /* stick a NULL at the end of the script, otherwise */ + /* parse_string_outer() runs off the end. */ + addr[image_get_data_size (hdr)] = 0; + addr += 8; + + /* + * Replace cr/lf with ; + */ + k = 0; + while (addr[k] != 0) { + if ((addr[k] == 10) || (addr[k] == 13)) { + addr[k] = ';'; + } + k++; + } + + run_command(addr, 0); + return 0; + } + + break; + + case AU_FIRMWARE: + case AU_NOR: + case AU_NAND: + start = au_image[i].start; + end = au_image[i].start + au_image[i].size - 1; + + /* + * do not update firmware when image is already in flash. + */ + if (au_image[i].type == AU_FIRMWARE) { + char *orig = (char*)start; + char *new = (char *)((char *)hdr + + image_get_header_size ()); + nbytes = image_get_data_size (hdr); + + while (--nbytes) { + if (*orig++ != *new++) { + break; + } + } + if (!nbytes) { + printf ("Skipping firmware update - " + "images are identical\n"); + break; + } + } + + /* unprotect the address range */ + if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) || + (au_image[i].type == AU_FIRMWARE)) { + flash_sect_protect (0, start, end); + } + + /* + * erase the address range. + */ + if (au_image[i].type != AU_NAND) { + printf ("Updating NOR FLASH with image %s\n", + au_image[i].name); + debug ("flash_sect_erase(%lx, %lx);\n", start, end); + flash_sect_erase (start, end); + } + + udelay(10000); + + /* strip the header - except for the kernel and ramdisk */ + if (au_image[i].type != AU_FIRMWARE) { + addr = (char *)hdr; + off = image_get_header_size (); + nbytes = image_get_image_size (hdr); + } else { + addr = (char *)((char *)hdr + image_get_header_size ()); + off = 0; + nbytes = image_get_data_size (hdr); + } + + /* + * copy the data from RAM to FLASH + */ + if (au_image[i].type != AU_NAND) { + debug ("flash_write(%p, %lx, %x)\n", + addr, start, nbytes); + rc = flash_write ((char *)addr, start, + (nbytes + 1) & ~1); + } else { + rc = -1; + } + if (rc != 0) { + printf ("Flashing failed due to error %d\n", rc); + return -1; + } + + /* + * check the dcrc of the copy + */ + if (au_image[i].type != AU_NAND) { + rc = crc32 (0, (uchar *)(start + off), + image_get_data_size (hdr)); + } + if (rc != image_get_dcrc (hdr)) { + printf ("Image %s Bad Data Checksum After COPY\n", + au_image[i].name); + return -1; + } + + /* protect the address range */ + /* this assumes that ONLY the firmware is protected! */ + if (((au_image[i].type & AU_FLAGMASK) == AU_PROTECT) || + (au_image[i].type == AU_FIRMWARE)) { + flash_sect_protect (1, start, end); + } + + break; + + default: + printf("Wrong image type selected!\n"); + } + + return 0; +} + +static void process_macros (const char *input, char *output) +{ + char c, prev; + const char *varname_start = NULL; + int inputcnt = strlen (input); + int outputcnt = CONFIG_SYS_CBSIZE; + int state = 0; /* 0 = waiting for '$' */ + /* 1 = waiting for '(' or '{' */ + /* 2 = waiting for ')' or '}' */ + /* 3 = waiting for ''' */ +#ifdef DEBUG_PARSER + char *output_start = output; + + printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", + strlen(input), input); +#endif + + prev = '\0'; /* previous character */ + + while (inputcnt && outputcnt) { + c = *input++; + inputcnt--; + + if (state != 3) { + /* remove one level of escape characters */ + if ((c == '\\') && (prev != '\\')) { + if (inputcnt-- == 0) + break; + prev = c; + c = *input++; + } + } + + switch (state) { + case 0: /* Waiting for (unescaped) $ */ + if ((c == '\'') && (prev != '\\')) { + state = 3; + break; + } + if ((c == '$') && (prev != '\\')) { + state++; + } else { + *(output++) = c; + outputcnt--; + } + break; + case 1: /* Waiting for ( */ + if (c == '(' || c == '{') { + state++; + varname_start = input; + } else { + state = 0; + *(output++) = '$'; + outputcnt--; + + if (outputcnt) { + *(output++) = c; + outputcnt--; + } + } + break; + case 2: /* Waiting for ) */ + if (c == ')' || c == '}') { + int i; + char envname[CONFIG_SYS_CBSIZE], *envval; + /* Varname # of chars */ + int envcnt = input - varname_start - 1; + + /* Get the varname */ + for (i = 0; i < envcnt; i++) { + envname[i] = varname_start[i]; + } + envname[i] = 0; + + /* Get its value */ + envval = getenv (envname); + + /* Copy into the line if it exists */ + if (envval != NULL) + while ((*envval) && outputcnt) { + *(output++) = *(envval++); + outputcnt--; + } + /* Look for another '$' */ + state = 0; + } + break; + case 3: /* Waiting for ' */ + if ((c == '\'') && (prev != '\\')) { + state = 0; + } else { + *(output++) = c; + outputcnt--; + } + break; + } + prev = c; + } + + if (outputcnt) + *output = 0; + +#ifdef DEBUG_PARSER + printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n", + strlen (output_start), output_start); +#endif +} + +/* + * this is called from board_init() after the hardware has been set up + * and is usable. That seems like a good time to do this. + * Right now the return value is ignored. + */ +int do_auto_update(void) +{ + block_dev_desc_t *stor_dev = NULL; + long sz; + int i, res, cnt, old_ctrlc; + char buffer[32]; + char str[80]; + int n; + + if (ide_dev_desc[0].type != DEV_TYPE_UNKNOWN) { + stor_dev = get_dev ("ide", 0); + if (stor_dev == NULL) { + debug ("ide: unknown device\n"); + return -1; + } + } + + if (fat_register_device (stor_dev, 1) != 0) { + debug ("Unable to register ide disk 0:1\n"); + return -1; + } + + /* + * Check if magic file is present + */ + if ((n = do_fat_read (AU_MAGIC_FILE, buffer, + sizeof(buffer), LS_NO)) <= 0) { + debug ("No auto_update magic file (n=%d)\n", n); + return -1; + } + +#ifdef CONFIG_AUTO_UPDATE_SHOW + board_auto_update_show (1); +#endif + puts("\nAutoUpdate Disk detected! Trying to update system...\n"); + + /* make sure that we see CTRL-C and save the old state */ + old_ctrlc = disable_ctrlc (0); + + /* just loop thru all the possible files */ + for (i = 0; i < N_AU_IMAGES; i++) { + /* + * Try to expand the environment var in the fname + */ + process_macros (au_image[i].name, str); + strcpy (au_image[i].name, str); + + printf("Reading %s ...", au_image[i].name); + /* just read the header */ + sz = do_fat_read (au_image[i].name, LOAD_ADDR, + image_get_header_size (), LS_NO); + debug ("read %s sz %ld hdr %d\n", + au_image[i].name, sz, image_get_header_size ()); + if (sz <= 0 || sz < image_get_header_size ()) { + puts(" not found\n"); + continue; + } + if (au_check_header_valid (i, sz) < 0) { + puts(" header not valid\n"); + continue; + } + sz = do_fat_read (au_image[i].name, LOAD_ADDR, + MAX_LOADSZ, LS_NO); + debug ("read %s sz %ld hdr %d\n", + au_image[i].name, sz, image_get_header_size ()); + if (sz <= 0 || sz <= image_get_header_size ()) { + puts(" not found\n"); + continue; + } + if (au_check_cksum_valid (i, sz) < 0) { + puts(" checksum not valid\n"); + continue; + } + puts(" done\n"); + + do { + res = au_do_update (i, sz); + /* let the user break out of the loop */ + if (ctrlc() || had_ctrlc ()) { + clear_ctrlc (); + break; + } + cnt++; + } while (res < 0); + } + + /* restore the old state */ + disable_ctrlc (old_ctrlc); + + puts("AutoUpdate finished\n\n"); +#ifdef CONFIG_AUTO_UPDATE_SHOW + board_auto_update_show (0); +#endif + + return 0; +} + +int auto_update(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + do_auto_update(); + + return 0; +} +U_BOOT_CMD( + autoupd, 1, 1, auto_update, + "Automatically update images", + "" +); +#endif /* CONFIG_AUTO_UPDATE */ |