Commit cdb97a6678826f85e7c69eae6a1c113d034c9b10

Authored by Andrei Safronov
1 parent dd520bf314

automatic update mechanism

Showing 4 changed files with 478 additions and 2 deletions Side-by-side Diff

board/mcc200/Makefile
... ... @@ -25,7 +25,7 @@
25 25  
26 26 LIB = $(obj)lib$(BOARD).a
27 27  
28   -COBJS := $(BOARD).o lcd.o
  28 +COBJS := $(BOARD).o lcd.o auto_update.o
29 29  
30 30 SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
31 31 OBJS := $(addprefix $(obj),$(COBJS))
board/mcc200/auto_update.c
  1 +/*
  2 + * (C) Copyright 2006
  3 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  4 + *
  5 + * This program is free software; you can redistribute it and/or
  6 + * modify it under the terms of the GNU General Public License as
  7 + * published by the Free Software Foundation; either version 2 of
  8 + * the License, or (at your option) any later version.
  9 + *
  10 + * This program is distributed in the hope that it will be useful,
  11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 + * GNU General Public License for more details.
  14 + *
  15 + * You should have received a copy of the GNU General Public License
  16 + * along with this program; if not, write to the Free Software
  17 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  18 + * MA 02111-1307 USA
  19 + */
  20 +#include <common.h>
  21 +#include <command.h>
  22 +#include <malloc.h>
  23 +#include <image.h>
  24 +#include <asm/byteorder.h>
  25 +#include <usb.h>
  26 +
  27 +#ifdef CFG_HUSH_PARSER
  28 +#include <hush.h>
  29 +#endif
  30 +
  31 +
  32 +#ifdef CONFIG_AUTO_UPDATE
  33 +
  34 +#ifndef CONFIG_USB_OHCI
  35 +#error "must define CONFIG_USB_OHCI"
  36 +#endif
  37 +
  38 +#ifndef CONFIG_USB_STORAGE
  39 +#error "must define CONFIG_USB_STORAGE"
  40 +#endif
  41 +
  42 +#ifndef CFG_HUSH_PARSER
  43 +#error "must define CFG_HUSH_PARSER"
  44 +#endif
  45 +
  46 +#if !(CONFIG_COMMANDS & CFG_CMD_FAT)
  47 +#error "must define CFG_CMD_FAT"
  48 +#endif
  49 +
  50 +/*
  51 + * Check whether a USB memory stick is plugged in.
  52 + * If one is found:
  53 + * 1) if prepare.img ist found load it into memory. If it is
  54 + * valid then run it.
  55 + * 2) if preinst.img is found load it into memory. If it is
  56 + * valid then run it. Update the EEPROM.
  57 + * 3) if firmw_01.img is found load it into memory. If it is valid,
  58 + * burn it into FLASH and update the EEPROM.
  59 + * 4) if kernl_01.img is found load it into memory. If it is valid,
  60 + * burn it into FLASH and update the EEPROM.
  61 + * 5) if app.img is found load it into memory. If it is valid,
  62 + * burn it into FLASH and update the EEPROM.
  63 + * 6) if disk.img is found load it into memory. If it is valid,
  64 + * burn it into FLASH and update the EEPROM.
  65 + * 7) if postinst.img is found load it into memory. If it is
  66 + * valid then run it. Update the EEPROM.
  67 + */
  68 +
  69 +#undef AU_DEBUG
  70 +
  71 +#undef debug
  72 +#ifdef AU_DEBUG
  73 +#define debug(fmt,args...) printf (fmt ,##args)
  74 +#else
  75 +#define debug(fmt,args...)
  76 +#endif /* AU_DEBUG */
  77 +
  78 +/* possible names of files on the USB stick. */
  79 +#define AU_FIRMWARE "u-boot.img"
  80 +#define AU_KERNEL "kernel.img"
  81 +
  82 +struct flash_layout
  83 +{
  84 + long start;
  85 + long end;
  86 +};
  87 +
  88 +/* layout of the FLASH. ST = start address, ND = end address. */
  89 +#define AU_FL_FIRMWARE_ST 0xfC000000
  90 +#define AU_FL_FIRMWARE_ND 0xfC03FFFF
  91 +#define AU_FL_KERNEL_ST 0xfC0C0000
  92 +#define AU_FL_KERNEL_ND 0xfC1BFFFF
  93 +
  94 +static int au_usb_stor_curr_dev; /* current device */
  95 +
  96 +/* index of each file in the following arrays */
  97 +#define IDX_FIRMWARE 0
  98 +#define IDX_KERNEL 1
  99 +
  100 +/* max. number of files which could interest us */
  101 +#define AU_MAXFILES 2
  102 +
  103 +/* pointers to file names */
  104 +char *aufile[AU_MAXFILES];
  105 +
  106 +/* sizes of flash areas for each file */
  107 +long ausize[AU_MAXFILES];
  108 +
  109 +/* array of flash areas start and end addresses */
  110 +struct flash_layout aufl_layout[AU_MAXFILES] = { \
  111 + {AU_FL_FIRMWARE_ST, AU_FL_FIRMWARE_ND,}, \
  112 + {AU_FL_KERNEL_ST, AU_FL_KERNEL_ND,}, \
  113 +};
  114 +
  115 +/* where to load files into memory */
  116 +#define LOAD_ADDR ((unsigned char *)0x00200000)
  117 +
  118 +/* the app is the largest image */
  119 +#define MAX_LOADSZ ausize[IDX_KERNEL]
  120 +
  121 +/*i2c address of the keypad status*/
  122 +#define I2C_PSOC_KEYPAD_ADDR 0x53
  123 +
  124 +/* keypad mask */
  125 +#define KEYPAD_ROW 3
  126 +#define KEYPAD_COL 3
  127 +#define KEYPAD_MASK_LO ((1<<(KEYPAD_COL-1+(KEYPAD_ROW*4-4)))&0xFF)
  128 +#define KEYPAD_MASK_HI ((1<<(KEYPAD_COL-1+(KEYPAD_ROW*4-4)))>>8)
  129 +
  130 +/* externals */
  131 +extern int fat_register_device(block_dev_desc_t *, int);
  132 +extern int file_fat_detectfs(void);
  133 +extern long file_fat_read(const char *, void *, unsigned long);
  134 +extern int i2c_read (unsigned char, unsigned int, int , unsigned char* , int);
  135 +extern int flash_sect_erase(ulong, ulong);
  136 +extern int flash_sect_protect (int, ulong, ulong);
  137 +extern int flash_write (char *, ulong, ulong);
  138 +/* change char* to void* to shutup the compiler */
  139 +extern block_dev_desc_t *get_dev (char*, int);
  140 +extern int u_boot_hush_start(void);
  141 +
  142 +int
  143 +au_check_cksum_valid(int idx, long nbytes)
  144 +{
  145 + image_header_t *hdr;
  146 + unsigned long checksum;
  147 +
  148 + hdr = (image_header_t *)LOAD_ADDR;
  149 +
  150 + if (nbytes != (sizeof(*hdr) + ntohl(hdr->ih_size)))
  151 + {
  152 + printf ("Image %s bad total SIZE\n", aufile[idx]);
  153 + return -1;
  154 + }
  155 + /* check the data CRC */
  156 + checksum = ntohl(hdr->ih_dcrc);
  157 +
  158 + if (crc32 (0, (uchar *)(LOAD_ADDR + sizeof(*hdr)), ntohl(hdr->ih_size))
  159 + != checksum)
  160 + {
  161 + printf ("Image %s bad data checksum\n", aufile[idx]);
  162 + return -1;
  163 + }
  164 + return 0;
  165 +}
  166 +
  167 +int
  168 +au_check_header_valid(int idx, long nbytes)
  169 +{
  170 + image_header_t *hdr;
  171 + unsigned long checksum;
  172 + unsigned char buf[4];
  173 +
  174 + hdr = (image_header_t *)LOAD_ADDR;
  175 + /* check the easy ones first */
  176 +#undef CHECK_VALID_DEBUG
  177 +#ifdef CHECK_VALID_DEBUG
  178 + printf("magic %#x %#x ", ntohl(hdr->ih_magic), IH_MAGIC);
  179 + printf("arch %#x %#x ", hdr->ih_arch, IH_CPU_ARM);
  180 + printf("size %#x %#lx ", ntohl(hdr->ih_size), nbytes);
  181 + printf("type %#x %#x ", hdr->ih_type, IH_TYPE_KERNEL);
  182 +#endif
  183 + if (nbytes < sizeof(*hdr))
  184 + {
  185 + printf ("Image %s bad header SIZE\n", aufile[idx]);
  186 + return -1;
  187 + }
  188 + if (ntohl(hdr->ih_magic) != IH_MAGIC || hdr->ih_arch != IH_CPU_PPC)
  189 + {
  190 + printf ("Image %s bad MAGIC or ARCH\n", aufile[idx]);
  191 + return -1;
  192 + }
  193 + /* check the hdr CRC */
  194 + checksum = ntohl(hdr->ih_hcrc);
  195 + hdr->ih_hcrc = 0;
  196 +
  197 + if (crc32 (0, (uchar *)hdr, sizeof(*hdr)) != checksum) {
  198 + printf ("Image %s bad header checksum\n", aufile[idx]);
  199 + return -1;
  200 + }
  201 + hdr->ih_hcrc = htonl(checksum);
  202 + /* check the type - could do this all in one gigantic if() */
  203 + if ((idx == IDX_FIRMWARE) && (hdr->ih_type != IH_TYPE_FIRMWARE)) {
  204 + printf ("Image %s wrong type\n", aufile[idx]);
  205 + return -1;
  206 + }
  207 + if ((idx == IDX_KERNEL) && (hdr->ih_type != IH_TYPE_KERNEL)) {
  208 + printf ("Image %s wrong type\n", aufile[idx]);
  209 + return -1;
  210 + }
  211 + /* recycle checksum */
  212 + checksum = ntohl(hdr->ih_size);
  213 + /* for kernel and app the image header must also fit into flash */
  214 + if (idx != IDX_FIRMWARE)
  215 + checksum += sizeof(*hdr);
  216 + /* check the size does not exceed space in flash. HUSH scripts */
  217 + /* all have ausize[] set to 0 */
  218 + if ((ausize[idx] != 0) && (ausize[idx] < checksum)) {
  219 + printf ("Image %s is bigger than FLASH\n", aufile[idx]);
  220 + return -1;
  221 + }
  222 + return 0;
  223 +}
  224 +
  225 +
  226 +int
  227 +au_do_update(int idx, long sz)
  228 +{
  229 + image_header_t *hdr;
  230 + char *addr;
  231 + long start, end;
  232 + int off, rc;
  233 + uint nbytes;
  234 +
  235 + hdr = (image_header_t *)LOAD_ADDR;
  236 +
  237 + /* execute a script */
  238 + if (hdr->ih_type == IH_TYPE_SCRIPT) {
  239 + addr = (char *)((char *)hdr + sizeof(*hdr));
  240 + /* stick a NULL at the end of the script, otherwise */
  241 + /* parse_string_outer() runs off the end. */
  242 + addr[ntohl(hdr->ih_size)] = 0;
  243 + addr += 8;
  244 + parse_string_outer(addr, FLAG_PARSE_SEMICOLON);
  245 + return 0;
  246 + }
  247 +
  248 + start = aufl_layout[idx].start;
  249 + end = aufl_layout[idx].end;
  250 +
  251 + /* unprotect the address range */
  252 + /* this assumes that ONLY the firmware is protected! */
  253 + if (idx == IDX_FIRMWARE) {
  254 +#undef AU_UPDATE_TEST
  255 +#ifdef AU_UPDATE_TEST
  256 + /* erase it where Linux goes */
  257 + start = aufl_layout[1].start;
  258 + end = aufl_layout[1].end;
  259 +#endif
  260 + flash_sect_protect(0, start, end);
  261 + }
  262 +
  263 + /*
  264 + * erase the address range.
  265 + */
  266 + debug ("flash_sect_erase(%lx, %lx);\n", start, end);
  267 + flash_sect_erase(start, end);
  268 + wait_ms(100);
  269 + /* strip the header - except for the kernel and ramdisk */
  270 + if (hdr->ih_type == IH_TYPE_KERNEL) {
  271 + addr = (char *)hdr;
  272 + off = sizeof(*hdr);
  273 + nbytes = sizeof(*hdr) + ntohl(hdr->ih_size);
  274 + } else {
  275 + addr = (char *)((char *)hdr + sizeof(*hdr));
  276 +#ifdef AU_UPDATE_TEST
  277 + /* copy it to where Linux goes */
  278 + if (idx == IDX_FIRMWARE)
  279 + start = aufl_layout[1].start;
  280 +#endif
  281 + off = 0;
  282 + nbytes = ntohl(hdr->ih_size);
  283 + }
  284 +
  285 + /* copy the data from RAM to FLASH */
  286 + debug ("flash_write(%p, %lx %x)\n", addr, start, nbytes);
  287 + rc = flash_write(addr, start, nbytes);
  288 + if (rc != 0) {
  289 + printf("Flashing failed due to error %d\n", rc);
  290 + return -1;
  291 + }
  292 +
  293 + /* check the dcrc of the copy */
  294 + if (crc32 (0, (uchar *)(start + off), ntohl(hdr->ih_size)) != ntohl(hdr->ih_dcrc)) {
  295 + printf ("Image %s Bad Data Checksum After COPY\n", aufile[idx]);
  296 + return -1;
  297 + }
  298 +
  299 + /* protect the address range */
  300 + /* this assumes that ONLY the firmware is protected! */
  301 + if (idx == IDX_FIRMWARE)
  302 + flash_sect_protect(1, start, end);
  303 + return 0;
  304 +}
  305 +
  306 +
  307 +/*
  308 + * this is called from board_init() after the hardware has been set up
  309 + * and is usable. That seems like a good time to do this.
  310 + * Right now the return value is ignored.
  311 + */
  312 +int
  313 +do_auto_update(void)
  314 +{
  315 + block_dev_desc_t *stor_dev;
  316 + long sz;
  317 + int i, res, bitmap_first, cnt, old_ctrlc, got_ctrlc;
  318 + char *env;
  319 + long start, end;
  320 + char keypad_status1[2] = {0,0}, keypad_status2[2] = {0,0};
  321 +
  322 + /*
  323 + * Read keypad status
  324 + */
  325 + i2c_read(I2C_PSOC_KEYPAD_ADDR, 0, 0, keypad_status1, 2);
  326 + wait_ms(500);
  327 + i2c_read(I2C_PSOC_KEYPAD_ADDR, 0, 0, keypad_status2, 2);
  328 +
  329 + /*
  330 + * Check keypad
  331 + */
  332 + if ( !(keypad_status1[0] & KEYPAD_MASK_HI) ||
  333 + (keypad_status1[0] != keypad_status2[0])) {
  334 + return 0;
  335 + }
  336 + if ( !(keypad_status1[1] & KEYPAD_MASK_LO) ||
  337 + (keypad_status1[1] != keypad_status2[1])) {
  338 + return 0;
  339 + }
  340 + au_usb_stor_curr_dev = -1;
  341 + /* start USB */
  342 + if (usb_stop() < 0) {
  343 + debug ("usb_stop failed\n");
  344 + return -1;
  345 + }
  346 + if (usb_init() < 0) {
  347 + debug ("usb_init failed\n");
  348 + return -1;
  349 + }
  350 + /*
  351 + * check whether a storage device is attached (assume that it's
  352 + * a USB memory stick, since nothing else should be attached).
  353 + */
  354 + au_usb_stor_curr_dev = usb_stor_scan(0);
  355 + if (au_usb_stor_curr_dev == -1) {
  356 + debug ("No device found. Not initialized?\n");
  357 + return -1;
  358 + }
  359 + /* check whether it has a partition table */
  360 + stor_dev = get_dev("usb", 0);
  361 + if (stor_dev == NULL) {
  362 + debug ("uknown device type\n");
  363 + return -1;
  364 + }
  365 + if (fat_register_device(stor_dev, 1) != 0) {
  366 + debug ("Unable to use USB %d:%d for fatls\n",
  367 + au_usb_stor_curr_dev, 1);
  368 + return -1;
  369 + }
  370 + if (file_fat_detectfs() != 0) {
  371 + debug ("file_fat_detectfs failed\n");
  372 + }
  373 +
  374 + /* initialize the array of file names */
  375 + memset(aufile, 0, sizeof(aufile));
  376 + aufile[IDX_FIRMWARE] = AU_FIRMWARE;
  377 + aufile[IDX_KERNEL] = AU_KERNEL;
  378 + /* initialize the array of flash sizes */
  379 + memset(ausize, 0, sizeof(ausize));
  380 + ausize[IDX_FIRMWARE] = (AU_FL_FIRMWARE_ND + 1) - AU_FL_FIRMWARE_ST;
  381 + ausize[IDX_KERNEL] = (AU_FL_KERNEL_ND + 1) - AU_FL_KERNEL_ST;
  382 + /*
  383 + * now check whether start and end are defined using environment
  384 + * variables.
  385 + */
  386 + start = -1;
  387 + end = 0;
  388 + env = getenv("firmware_st");
  389 + if (env != NULL)
  390 + start = simple_strtoul(env, NULL, 16);
  391 + env = getenv("firmware_nd");
  392 + if (env != NULL)
  393 + end = simple_strtoul(env, NULL, 16);
  394 + if (start >= 0 && end && end > start) {
  395 + ausize[IDX_FIRMWARE] = (end + 1) - start;
  396 + aufl_layout[0].start = start;
  397 + aufl_layout[0].end = end;
  398 + }
  399 + start = -1;
  400 + end = 0;
  401 + env = getenv("kernel_st");
  402 + if (env != NULL)
  403 + start = simple_strtoul(env, NULL, 16);
  404 + env = getenv("kernel_nd");
  405 + if (env != NULL)
  406 + end = simple_strtoul(env, NULL, 16);
  407 + if (start >= 0 && end && end > start) {
  408 + ausize[IDX_KERNEL] = (end + 1) - start;
  409 + aufl_layout[1].start = start;
  410 + aufl_layout[1].end = end;
  411 + }
  412 + /* make certain that HUSH is runnable */
  413 + u_boot_hush_start();
  414 + /* make sure that we see CTRL-C and save the old state */
  415 + old_ctrlc = disable_ctrlc(0);
  416 +
  417 + bitmap_first = 0;
  418 + /* just loop thru all the possible files */
  419 + for (i = 0; i < AU_MAXFILES; i++) {
  420 + /* just read the header */
  421 + sz = file_fat_read(aufile[i], LOAD_ADDR, sizeof(image_header_t));
  422 + debug ("read %s sz %ld hdr %d\n",
  423 + aufile[i], sz, sizeof(image_header_t));
  424 + if (sz <= 0 || sz < sizeof(image_header_t)) {
  425 + debug ("%s not found\n", aufile[i]);
  426 + continue;
  427 + }
  428 + if (au_check_header_valid(i, sz) < 0) {
  429 + debug ("%s header not valid\n", aufile[i]);
  430 + continue;
  431 + }
  432 + sz = file_fat_read(aufile[i], LOAD_ADDR, MAX_LOADSZ);
  433 + debug ("read %s sz %ld hdr %d\n",
  434 + aufile[i], sz, sizeof(image_header_t));
  435 + if (sz <= 0 || sz <= sizeof(image_header_t)) {
  436 + debug ("%s not found\n", aufile[i]);
  437 + continue;
  438 + }
  439 + if (au_check_cksum_valid(i, sz) < 0) {
  440 + debug ("%s checksum not valid\n", aufile[i]);
  441 + continue;
  442 + }
  443 + /* this is really not a good idea, but it's what the */
  444 + /* customer wants. */
  445 + cnt = 0;
  446 + got_ctrlc = 0;
  447 + do {
  448 + res = au_do_update(i, sz);
  449 + /* let the user break out of the loop */
  450 + if (ctrlc() || had_ctrlc()) {
  451 + clear_ctrlc();
  452 + if (res < 0)
  453 + got_ctrlc = 1;
  454 + break;
  455 + }
  456 + cnt++;
  457 +#ifdef AU_TEST_ONLY
  458 + } while (res < 0 && cnt < 3);
  459 + if (cnt < 3)
  460 +#else
  461 + } while (res < 0);
  462 +#endif
  463 + }
  464 + usb_stop();
  465 + /* restore the old state */
  466 + disable_ctrlc(old_ctrlc);
  467 + return 0;
  468 +}
  469 +#endif /* CONFIG_AUTO_UPDATE */
board/mcc200/mcc200.c
... ... @@ -44,6 +44,7 @@
44 44  
45 45 extern flash_info_t flash_info[]; /* FLASH chips info */
46 46  
  47 +extern int do_auto_update(void);
47 48 ulong flash_get_size (ulong base, int banknum);
48 49  
49 50 #ifndef CFG_RAMBOOT
... ... @@ -227,6 +228,10 @@
227 228 {
228 229 ulong flash_sup_end, snum;
229 230  
  231 +#ifdef CONFIG_AUTO_UPDATE
  232 + /* this has priority over all else */
  233 + do_auto_update();
  234 +#endif
230 235 /*
231 236 * Adjust flash start and offset to detected values
232 237 */
include/configs/mcc200.h
... ... @@ -94,6 +94,8 @@
94 94 #define CONFIG_USB_OHCI
95 95 #define ADD_USB_CMD CFG_CMD_USB | CFG_CMD_FAT
96 96 #define CONFIG_USB_STORAGE
  97 +/* automatic software updates (see board/mcc200/auto_update.c) */
  98 +#define CONFIG_AUTO_UPDATE 1
97 99  
98 100 /*
99 101 * Supported commands
... ... @@ -173,7 +175,7 @@
173 175 * I2C configuration
174 176 */
175 177 #define CONFIG_HARD_I2C 1 /* I2C with hardware support */
176   -#define CFG_I2C_MODULE 1 /* Select I2C module #1 or #2 */
  178 +#define CFG_I2C_MODULE 2 /* Select I2C module #1 or #2 */
177 179  
178 180 #define CFG_I2C_SPEED 100000 /* 100 kHz */
179 181 #define CFG_I2C_SLAVE 0x7F