uboot/common/update.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2008 Semihalf
   3 *
   4 * Written by: Rafal Czubak <rcz@semihalf.com>
   5 *             Bartlomiej Sieka <tur@semihalf.com>
   6 *
   7 * SPDX-License-Identifier:     GPL-2.0+
   8 */
   9
  10#include <common.h>
  11
  12#if !(defined(CONFIG_FIT) && defined(CONFIG_OF_LIBFDT))
  13#error "CONFIG_FIT and CONFIG_OF_LIBFDT are required for auto-update feature"
  14#endif
  15
  16#if defined(CONFIG_SYS_NO_FLASH)
  17#error "CONFIG_SYS_NO_FLASH defined, but FLASH is required for auto-update feature"
  18#endif
  19
  20#include <command.h>
  21#include <flash.h>
  22#include <net.h>
  23#include <net/tftp.h>
  24#include <malloc.h>
  25
  26/* env variable holding the location of the update file */
  27#define UPDATE_FILE_ENV         "updatefile"
  28
  29/* set configuration defaults if needed */
  30#ifndef CONFIG_UPDATE_LOAD_ADDR
  31#define CONFIG_UPDATE_LOAD_ADDR 0x100000
  32#endif
  33
  34#ifndef CONFIG_UPDATE_TFTP_MSEC_MAX
  35#define CONFIG_UPDATE_TFTP_MSEC_MAX     100
  36#endif
  37
  38#ifndef CONFIG_UPDATE_TFTP_CNT_MAX
  39#define CONFIG_UPDATE_TFTP_CNT_MAX      0
  40#endif
  41
  42extern ulong TftpRRQTimeoutMSecs;
  43extern int TftpRRQTimeoutCountMax;
  44extern flash_info_t flash_info[];
  45extern ulong load_addr;
  46
  47static uchar *saved_prot_info;
  48
  49static int update_load(char *filename, ulong msec_max, int cnt_max, ulong addr)
  50{
  51        int size, rv;
  52        ulong saved_timeout_msecs;
  53        int saved_timeout_count;
  54        char *saved_netretry, *saved_bootfile;
  55
  56        rv = 0;
  57        /* save used globals and env variable */
  58        saved_timeout_msecs = TftpRRQTimeoutMSecs;
  59        saved_timeout_count = TftpRRQTimeoutCountMax;
  60        saved_netretry = strdup(getenv("netretry"));
  61        saved_bootfile = strdup(BootFile);
  62
  63        /* set timeouts for auto-update */
  64        TftpRRQTimeoutMSecs = msec_max;
  65        TftpRRQTimeoutCountMax = cnt_max;
  66
  67        /* we don't want to retry the connection if errors occur */
  68        setenv("netretry", "no");
  69
  70        /* download the update file */
  71        load_addr = addr;
  72        copy_filename(BootFile, filename, sizeof(BootFile));
  73        size = NetLoop(TFTPGET);
  74
  75        if (size < 0)
  76                rv = 1;
  77        else if (size > 0)
  78                flush_cache(addr, size);
  79
  80        /* restore changed globals and env variable */
  81        TftpRRQTimeoutMSecs = saved_timeout_msecs;
  82        TftpRRQTimeoutCountMax = saved_timeout_count;
  83
  84        setenv("netretry", saved_netretry);
  85        if (saved_netretry != NULL)
  86                free(saved_netretry);
  87
  88        if (saved_bootfile != NULL) {
  89                copy_filename(BootFile, saved_bootfile, sizeof(BootFile));
  90                free(saved_bootfile);
  91        }
  92
  93        return rv;
  94}
  95
  96static int update_flash_protect(int prot, ulong addr_first, ulong addr_last)
  97{
  98        uchar *sp_info_ptr;
  99        ulong s;
 100        int i, bank, cnt;
 101        flash_info_t *info;
 102
 103        sp_info_ptr = NULL;
 104
 105        if (prot == 0) {
 106                saved_prot_info =
 107                        calloc(CONFIG_SYS_MAX_FLASH_BANKS * CONFIG_SYS_MAX_FLASH_SECT, 1);
 108                if (!saved_prot_info)
 109                        return 1;
 110        }
 111
 112        for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
 113                cnt = 0;
 114                info = &flash_info[bank];
 115
 116                /* Nothing to do if the bank doesn't exist */
 117                if (info->sector_count == 0)
 118                        return 0;
 119
 120                /* Point to current bank protection information */
 121                sp_info_ptr = saved_prot_info + (bank * CONFIG_SYS_MAX_FLASH_SECT);
 122
 123                /*
 124                 * Adjust addr_first or addr_last if we are on bank boundary.
 125                 * Address space between banks must be continuous for other
 126                 * flash functions (like flash_sect_erase or flash_write) to
 127                 * succeed. Banks must also be numbered in correct order,
 128                 * according to increasing addresses.
 129                 */
 130                if (addr_last > info->start[0] + info->size - 1)
 131                        addr_last = info->start[0] + info->size - 1;
 132                if (addr_first < info->start[0])
 133                        addr_first = info->start[0];
 134
 135                for (i = 0; i < info->sector_count; i++) {
 136                        /* Save current information about protected sectors */
 137                        if (prot == 0) {
 138                                s = info->start[i];
 139                                if ((s >= addr_first) && (s <= addr_last))
 140                                        sp_info_ptr[i] = info->protect[i];
 141
 142                        }
 143
 144                        /* Protect/unprotect sectors */
 145                        if (sp_info_ptr[i] == 1) {
 146#if defined(CONFIG_SYS_FLASH_PROTECTION)
 147                                if (flash_real_protect(info, i, prot))
 148                                        return 1;
 149#else
 150                                info->protect[i] = prot;
 151#endif
 152                                cnt++;
 153                        }
 154                }
 155
 156                if (cnt) {
 157                        printf("%sProtected %d sectors\n",
 158                                                prot ? "": "Un-", cnt);
 159                }
 160        }
 161
 162        if((prot == 1) && saved_prot_info)
 163                free(saved_prot_info);
 164
 165        return 0;
 166}
 167
 168static int update_flash(ulong addr_source, ulong addr_first, ulong size)
 169{
 170        ulong addr_last = addr_first + size - 1;
 171
 172        /* round last address to the sector boundary */
 173        if (flash_sect_roundb(&addr_last) > 0)
 174                return 1;
 175
 176        if (addr_first >= addr_last) {
 177                printf("Error: end address exceeds addressing space\n");
 178                return 1;
 179        }
 180
 181        /* remove protection on processed sectors */
 182        if (update_flash_protect(0, addr_first, addr_last) > 0) {
 183                printf("Error: could not unprotect flash sectors\n");
 184                return 1;
 185        }
 186
 187        printf("Erasing 0x%08lx - 0x%08lx", addr_first, addr_last);
 188        if (flash_sect_erase(addr_first, addr_last) > 0) {
 189                printf("Error: could not erase flash\n");
 190                return 1;
 191        }
 192
 193        printf("Copying to flash...");
 194        if (flash_write((char *)addr_source, addr_first, size) > 0) {
 195                printf("Error: could not copy to flash\n");
 196                return 1;
 197        }
 198        printf("done\n");
 199
 200        /* enable protection on processed sectors */
 201        if (update_flash_protect(1, addr_first, addr_last) > 0) {
 202                printf("Error: could not protect flash sectors\n");
 203                return 1;
 204        }
 205
 206        return 0;
 207}
 208
 209static int update_fit_getparams(const void *fit, int noffset, ulong *addr,
 210                                                ulong *fladdr, ulong *size)
 211{
 212        const void *data;
 213
 214        if (fit_image_get_data(fit, noffset, &data, (size_t *)size))
 215                return 1;
 216
 217        if (fit_image_get_load(fit, noffset, (ulong *)fladdr))
 218                return 1;
 219
 220        *addr = (ulong)data;
 221
 222        return 0;
 223}
 224
 225int update_tftp(ulong addr)
 226{
 227        char *filename, *env_addr;
 228        int images_noffset, ndepth, noffset;
 229        ulong update_addr, update_fladdr, update_size;
 230        void *fit;
 231        int ret = 0;
 232
 233        /* use already present image */
 234        if (addr)
 235                goto got_update_file;
 236
 237        printf("Auto-update from TFTP: ");
 238
 239        /* get the file name of the update file */
 240        filename = getenv(UPDATE_FILE_ENV);
 241        if (filename == NULL) {
 242                printf("failed, env. variable '%s' not found\n",
 243                                                        UPDATE_FILE_ENV);
 244                return 1;
 245        }
 246
 247        printf("trying update file '%s'\n", filename);
 248
 249        /* get load address of downloaded update file */
 250        if ((env_addr = getenv("loadaddr")) != NULL)
 251                addr = simple_strtoul(env_addr, NULL, 16);
 252        else
 253                addr = CONFIG_UPDATE_LOAD_ADDR;
 254
 255
 256        if (update_load(filename, CONFIG_UPDATE_TFTP_MSEC_MAX,
 257                                        CONFIG_UPDATE_TFTP_CNT_MAX, addr)) {
 258                printf("Can't load update file, aborting auto-update\n");
 259                return 1;
 260        }
 261
 262got_update_file:
 263        fit = (void *)addr;
 264
 265        if (!fit_check_format((void *)fit)) {
 266                printf("Bad FIT format of the update file, aborting "
 267                                                        "auto-update\n");
 268                return 1;
 269        }
 270
 271        /* process updates */
 272        images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
 273
 274        ndepth = 0;
 275        noffset = fdt_next_node(fit, images_noffset, &ndepth);
 276        while (noffset >= 0 && ndepth > 0) {
 277                if (ndepth != 1)
 278                        goto next_node;
 279
 280                printf("Processing update '%s' :",
 281                        fit_get_name(fit, noffset, NULL));
 282
 283                if (!fit_image_verify(fit, noffset)) {
 284                        printf("Error: invalid update hash, aborting\n");
 285                        ret = 1;
 286                        goto next_node;
 287                }
 288
 289                printf("\n");
 290                if (update_fit_getparams(fit, noffset, &update_addr,
 291                                        &update_fladdr, &update_size)) {
 292                        printf("Error: can't get update parameteres, "
 293                                                                "aborting\n");
 294                        ret = 1;
 295                        goto next_node;
 296                }
 297                if (update_flash(update_addr, update_fladdr, update_size)) {
 298                        printf("Error: can't flash update, aborting\n");
 299                        ret = 1;
 300                        goto next_node;
 301                }
 302next_node:
 303                noffset = fdt_next_node(fit, noffset, &ndepth);
 304        }
 305
 306        return ret;
 307}
 308