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