apps/bootblocktool-R1_3_0/bootblocktool.c

Go to the documentation of this file.
00001 /*!***************************************************************************
00002 *!
00003 *! FILE NAME  : bootblocktool.c
00004 *!
00005 *! DESCRIPTION: Handles bootblock parameters
00006 *!
00007 *! ---------------------------------------------------------------------------
00008 *! (C) Copyright 2000-2007, Axis Communications AB, LUND, SWEDEN
00009 *! 
00010 *! This program is free software; you can redistribute it and/or 
00011 *! modify it under the terms of the GNU General Public License 
00012 *! as published by the Free Software Foundation; either 
00013 *! version 2 of the License, or (at your option) any later 
00014 *! version.
00015 *! 
00016 *! This program is distributed in the hope that it will be useful,
00017 *! but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 *! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 *! GNU General Public License for more details.
00020 *! 
00021 *! You should have received a copy of the GNU General Public License
00022 *! along with this program; if not, write to the Free Software
00023 *! Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024 *! ---------------------------------------------------------------------------
00025 *! HISTORY
00026 *!
00027 *! DATE         NAME               CHANGES
00028 *! ----         ----               -------
00029 *! $Log: bootblocktool.c,v $
00030 *! Revision 1.1.1.1  2008/11/27 20:04:01  elphel
00031 *!
00032 *!
00033 *! Revision 1.1.1.1  2007/06/29 12:39:49  elphel
00034 *! This is a fresh tree based on elphel353-2.10
00035 *!
00036 *! Revision 1.1  2007/06/29 12:39:49  spectr_rain
00037 *! *** empty log message ***
00038 *!
00039 *! Revision 1.28  2007/02/23 14:26:11  karljope
00040 *! Merged task_branch--nandflash_support
00041 *!
00042 *! Revision 1.27  2007/01/10 15:43:05  karljope
00043 *! Copyright statement added.
00044 *!
00045 *! Revision 1.26.2.11  2007/02/21 18:11:01  karljope
00046 *! Sync with HEAD
00047 *!
00048 *! Revision 1.26.2.10  2007/02/13 13:14:19  karljope
00049 *! Made it compile for kernels older than 2.6.19 again
00050 *!
00051 *! Revision 1.26.2.9  2007/02/07 16:00:22  karljope
00052 *! * Removed inclusion of linux/compiler.h as the file is no longer available.
00053 *!   What was it used for? Compiles fine without it anyway.
00054 *! * Added a space in HTML_END to avoid warning. Why do we use it when we
00055 *!   obviously don't intend to print anything?
00056 *!
00057 *! Revision 1.26.2.8  2007/01/23 21:41:57  ricardw
00058 *! Cleaned file of all tabs.
00059 *!
00060 *! Revision 1.26.2.7  2007/01/19 15:36:13  ricardw
00061 *! Freed wrong pointer in readParam loop, fixed. Also free parvalue in same
00062 *! function if caller is not interested in value.
00063 *!
00064 *! Revision 1.26.2.6  2007/01/19 14:44:35  ricardw
00065 *! Fixes from review 070115:
00066 *! Added checks so that the implementation limit of max one block of parameters
00067 *! and max one page per parameter are not exceeded.
00068 *! Removed tabs in file.
00069 *! Plug memory leak in loop in readParam.
00070 *! Miscellaneous code cleanup.
00071 *!
00072 *! Revision 1.26.2.5  2006/11/22 12:30:50  ricardw
00073 *! Name change of rescue partition /dev/part/crescue -> /dev/part/rescue.
00074 *!
00075 *! Revision 1.26.2.4  2006/11/14 07:34:54  ricardw
00076 *! Conditonally use fwinfo area only when fwinfo set in axis config.
00077 *!
00078 *! Revision 1.26.2.3  2006/11/09 15:46:29  ricardw
00079 *! imageinfo -> fwinfo (name change).
00080 *! Added backwards compatbility for old kernels (<2.6.18, <2.6.0).
00081 *!
00082 *! Revision 1.26.2.2  2006/10/13 15:31:08  ricardw
00083 *! Modified to use image info area instead of hard coded addresses.
00084 *!
00085 *! Revision 1.26.2.1  2006/10/13 13:51:20  ricardw
00086 *! Initial support for NAND flash.
00087 *!
00088 *! Revision 1.26  2006/08/14 12:01:53  martinnn
00089 *! Added option -err which sets exit status on errors.
00090 *!
00091 *! Revision 1.25  2004/11/08 14:54:11  ulfo
00092 *! Corrected the HTTP header
00093 *!
00094 *! Revision 1.24  2004/02/11 17:52:31  henriken
00095 *! '-w' argument parsing bug fixes:
00096 *!
00097 *! * ignore variables submitted without a value
00098 *! * stop on variables with empty name
00099 *!
00100 *! Revision 1.23  2002/08/04 19:22:31  andorzn
00101 *! * Added include of errrno.h.
00102 *! * Added syslog messages.
00103 *! * Added and corrected logging/printing of errno values.
00104 *! * Removed some magic numbers.
00105 *!
00106 *! Revision 1.22  2002/01/23 13:48:00  johana
00107 *! Clarified/reformatted usage.
00108 *!
00109 *! Revision 1.21  2002/01/22 14:26:13  orjanf
00110 *! Added -backup option (changes flash offset and magic).
00111 *!
00112 *! Revision 1.20  2001/06/12 12:06:41  jonashg
00113 *! Print usage instead of segfault.
00114 *!
00115 *! Revision 1.19  2001/03/27 14:16:59  jonashg
00116 *! Removed warning message. sftpd will be modified.
00117 *!
00118 *! Revision 1.18  2000/12/19 09:40:29  pkj
00119 *! Added option -nocgi (must be the first option supplied) to prevent
00120 *! output of Content-Type when run through a web-script (PHP).
00121 *!
00122 *! Revision 1.17  2000/11/22 17:27:22  johana
00123 *! Fixed parsing bugs for -w and -c (it worked if there happend to be
00124 *! 0x00 after the argv, easaly detected if tested on host,
00125 *! the bugs are probably in apps/paramtool as well where that code was taken from,
00126 *! but there are no (good) reasons to use paramtool nowadays anyway:-)
00127 *! Fixed null terminating of name in readParamAt. (It happend to work if the
00128 *! allocated memory contained 0x00..)
00129 *!
00130 *! Changed all FILE* operations to the unbuffered versions using filedescriptors,
00131 *! fseek and fwrite was very weird on my host.
00132 *!
00133 *! Revision 1.16  2000/08/30 12:07:02  olak
00134 *! added printf used by sftpd
00135 *!
00136 *! Revision 1.15  2000/08/24 16:45:33  johana
00137 *! Added unistd.h to remove warning (getpid())
00138 *!
00139 *! Revision 1.14  2000/08/09 18:03:42  finn
00140 *! More cleanup.
00141 *!
00142 *! Revision 1.13  2000/08/07 16:05:17  finn
00143 *! Cleanup.
00144 *!
00145 *! Revision 1.12  2000/07/04 13:21:02  johana
00146 *! Support same parameters as paramtool: -w and -c
00147 *! Added -lenv option to print all parameters in setenv format.
00148 *!
00149 *!***************************************************************************/
00150 /* $Id: bootblocktool.c,v 1.1.1.1 2008/11/27 20:04:01 elphel Exp $ */
00151 
00152 /****************** INCLUDE FILES SECTION ***********************************/
00153 
00154 #include <stdlib.h>
00155 #include <stdio.h>
00156 #include <string.h>
00157 #include <unistd.h>
00158 #include <fcntl.h>
00159 #include <errno.h>
00160 #include <syslog.h>
00161 #include <sys/ioctl.h>
00162 #include <linux/version.h>
00163 #if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 8)
00164 #if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 19)
00165 #include <linux/compiler.h>
00166 #endif
00167 #include <mtd/mtd-user.h>
00168 #else
00169 #include <linux/mtd/mtd.h>
00170 #endif
00171 #ifdef USE_FWINFO_AREA
00172 #include <fwinfo.h>
00173 #endif
00174 
00175 /****************** CONSTANT AND MACRO SECTION ******************************/
00176 
00177 #define EMPTYMAGIC         0xffffffff   /* what the flash looks like empty */
00178 #define PARAMMAGIC_PRIMARY 0xbeefcace   /* default */
00179 #define PARAMMAGIC_BACKUP  0xdeadbabe   /* backup */
00180 
00181 #define MAX_PARAM_NAME_LEN 0xff /* format has name length in single byte */
00182 #define MAX_RECORD_LEN   0xffff /* format has record length in two bytes */
00183 
00184 #define ERR_NO_MAGIC -3
00185 #define ERR_END_OF_PARAMS -2
00186 #define ERR_OTHER -1
00187 #define NO_ERROR   0
00188 
00189 #define NAND_NOR_COMPATIBILITY_MODE (1)
00190 
00191 /* Given a len, round up to the next multiple of pagesize */
00192 #define ROUND_UP(len, pagesize) ((((len) - 1) & ~((pagesize) - 1)) + (pagesize))
00193 /* Given an offset, return 1 if it refers to the first address of a block */
00194 #define BLOCK_START(offset, blocksize) (((offset) & ((blocksize) -1)) == 0)
00195 /* Given an offset, keep the bits describing the block no */
00196 #define BLOCK_ADDR(offset, blocksize) ((offset) & ~((blocksize) -1))
00197 
00198 static const char *dev = "/dev/part/rescue";  /* bootblock partition */
00199 
00200 const char usage[] =
00201 "Usage: bootblocktool [options] command\n"
00202 "Options:\n"
00203 "  -backup    Makes all subsequent parameters pertain to the backup block\n"
00204 "  -nocgi     Disable CGI detection\n"
00205 "  -d device  The device to use\n"
00206 "  -err       Set exit status != 0 on parameter errors\n"
00207 "Commands:\n"
00208 "  -x name1 name2 ...          ; get\n"
00209 "  -c name:name2:name3         ; get/check\n"
00210 "  -a name1 value1 name2 value2 ... ; set\n"
00211 "  -w name=value:name2=value2       ; set\n"
00212 "  -l     ; list parameters\n"
00213 "  -lenv  ; list parameters in setenv format\n"
00214 ;
00215 
00216 const char HTML_END[] = " ";
00217 /*"</pre>\n</BODY></HTML>\n"; */
00218 
00219 //#define DEBUG
00220 #ifdef DEBUG
00221 #define D(x) x
00222 #define close(x) printf("close\n"); close(x)
00223 
00224 int open_dbg(const char* name, int type)
00225 {
00226   printf("open(%s, %i)\n", name, type); 
00227   return open(name, type);
00228 }
00229 #define open(name, type) open_dbg(name, type)
00230 
00231 int lseek_dbg(int f, long offset, int whence)
00232 {
00233   int res;
00234 //  printf(" ftell: %li\n", ftell(f));
00235 
00236   res = lseek(f, offset, whence);
00237   printf(" seek to %li %i result: %i %s\n", offset, whence, 
00238          res, res!=offset?"!!!!":""); 
00239 //  printf(" ftell: %li\n", ftell(f));
00240   return res;
00241   
00242 }
00243 #define lseek(f, offset, whence) lseek_dbg(f, offset, whence)
00244 #else
00245 #define D(x)
00246 #endif
00247 
00248 /***************** TYPE DEFINITION SECTION **********************************/
00249 
00250 typedef enum {SCRIPT, NAMEVALUE } Toutput_type;
00251 
00252 /****************** LOCAL FUNCTION DECLARATION SECTION **********************/
00253 
00254 static void printUsage(void);
00255 static void die(const char *);
00256 
00257 static void listParams(Toutput_type output_type);
00258 
00259 static int readParam(const char *name, char **value, int *firstfree);
00260 static int writeParam(const char *name, const char *value);
00261 
00262 static int writeMagic(int file, int *offset);
00263 
00264 static int readParamAt(int f, int offset,
00265                        char **name, int *nameLen,
00266                        char **value, int *valueLen,
00267                        int *totlen);
00268 static int writeParamAt(int f, int offset, const char *name,
00269                         const char *value);
00270 
00271 static void skipBadBlocks(int fd, int *offset);
00272 
00273 static int getChipParams(void);
00274 
00275 static int setFlashParams(void);
00276 
00277 /****************** GLOBAL VARIABLE DECLARATION SECTION *********************/
00278 
00279 /********************** LOCAL VARIABLE SECTION ****************************/
00280 
00281 static int useHTML = 0;
00282 static int setExitErr = 0;
00283 static int exitStat = 0;
00284 
00285 static int PARAMMAGIC = PARAMMAGIC_PRIMARY;
00286 
00287 static int FlashOffset; /* first address in flash used for params */
00288 static int FlashEnd; /* location after highest location we may write to */
00289 
00290 static int nandFlash = 0; /* 0 for nor, 1 for nand */
00291 /* The following two only relevant for nand flash */
00292 static unsigned int blockSize;
00293 static unsigned int pageSize;
00294 
00295 /********************** FUNCTION DEFINITION SECTION ************************/
00296 
00297 int
00298 main(int argc, char **argv)
00299 {
00300   int dummy;
00301   const char *method;
00302   
00303   argc--;
00304   argv++;
00305 
00306   if (argc > 0 && !strcmp(*argv, "-nocgi"))
00307   {
00308     argc--;
00309     argv++;
00310   }
00311   else if ((method = getenv("REQUEST_METHOD")))
00312   {
00313     useHTML = 1;
00314     printf("Content-type: text/plain\r\n\r\n");
00315   }
00316 #if 0
00317   if (useHTML)
00318   {
00319     printf("<HTML><BODY>\n");
00320     printf("<pre>\n");
00321   }
00322 #endif
00323   if (argc > 0 && !strcmp(*argv, "-err"))
00324   {
00325     setExitErr = 1;
00326     argc--;
00327     argv++;
00328   }
00329   if (argc < 1)
00330   {
00331     printUsage();
00332   }
00333 
00334   openlog("bootblocktool", LOG_PID, LOG_USER);
00335 
00336   if (setFlashParams() < 0)
00337     return 1;
00338 
00339   while (argc)
00340   {
00341     /* Change offset and magic to the backup block. (This option must be
00342        checked first since arguments are processed in the order they appear
00343        on the command line.) */
00344     if (!strcmp("-backup", *argv))
00345     {
00346       argc--;
00347       argv++;
00348       PARAMMAGIC = PARAMMAGIC_BACKUP;
00349       if (setFlashParams() < 0)
00350         return 1;
00351     }
00352     else if (!strcmp("-x", *argv))
00353     {
00354       argc--;
00355       argv++;
00356       if (argc < 1) {
00357         printUsage();
00358       }
00359       /* Read any number of params from device.  */
00360       while (argc > 0)
00361       {
00362         /* Extract a bootparam value.  */
00363         char *value = 0;
00364         if (!readParam(*argv, &value, &dummy))
00365         {
00366           /* Print to stdout.  */
00367           printf("%s\n", value);
00368           free(value);
00369         }
00370         else
00371         {
00372           fprintf(stderr, "Warning: Parameter %s not found.\n", *argv);
00373           exitStat = 1;
00374         }
00375         argc--;
00376         argv++;
00377       }
00378     }
00379     else if (!strcmp("-l", *argv))
00380     {
00381       argc--;
00382       argv++;
00383       /* List all parameters.  */
00384       listParams(NAMEVALUE);
00385     }
00386     else if (!strcmp("-lenv", *argv))
00387     {
00388       argc--;
00389       argv++;
00390       /* List all parameters.  */
00391       listParams(SCRIPT);
00392     }
00393     else if (!strcmp("-a", *argv))
00394     {
00395       argc--;
00396       argv++;
00397       if (argc < 1) {
00398         printUsage();
00399       }
00400       /* Write any number of params to device. */
00401       while (argc > 1)
00402       {
00403         if (writeParam(argv[0], argv[1]))
00404         {
00405           fprintf(stderr, "Warning: Parameter %s already exists.\n", argv[0]);
00406           exitStat = 1;
00407         }
00408         argc -= 2;
00409         argv += 2;
00410       }
00411     }
00412     else if (!strcmp("-d", *argv))
00413     {
00414       /* Specify a device to use. */
00415       dev = argv[1];
00416       D(printf("New device set: \"%s\"\n", dev));
00417       argv += 2;
00418       argc -= 2;
00419       /* must set flash parameters again now */
00420       if (setFlashParams() < 0)
00421         return 1;
00422     }
00423     else if (!strcmp("-c", *argv))
00424     {
00425       /* -c&SERNO:HWID:BRAND */
00426       char *name;
00427       char *sep;
00428 
00429       argc--;
00430       argv++;
00431       if (argc < 1) {
00432         printUsage();
00433       }
00434       name = *argv;
00435       sep = strchr(*argv, ':');
00436 
00437       /* Read any number of params from device. */
00438       while (name != NULL && *name != '\0')
00439       {
00440         /* Extract a bootparam value. */
00441         char *value = 0;
00442         if (sep != NULL)
00443         {
00444           *sep = '\0'; /* terminate the name */
00445           sep++;
00446         }
00447 
00448         if (!readParam(name, &value, &dummy))
00449         {
00450           /* Print to stdout. */
00451           if (name != *argv)
00452           {
00453             printf(" ");
00454           }
00455           printf("%s", value);
00456           free(value);
00457         }
00458         else
00459         {
00460           fprintf(stderr, "Warning: Parameter %s not found.\n", name);
00461           printf("Warning: Parameter %s not found.\n", name);
00462           exitStat = 1;
00463         }
00464         name = sep;
00465         if (sep)
00466         {
00467           sep = strchr(sep, ':');
00468         }
00469       }
00470       argc--;
00471       argv++;
00472     }
00473     else if (!strcmp("-w", *argv))
00474     {
00475       /* -w&SERNO=0800460814db:BRAND=Axis:HWID=400 */
00476       char *name;
00477       char *value;
00478       char *sep = NULL;
00479 
00480       argc--;
00481       argv++;
00482       if (argc < 1) {
00483         printUsage();
00484       }
00485       name = *argv;
00486       value = strchr(name, '=');
00487       sep = strchr(name, ':');
00488       if (value)
00489       {
00490         if (sep && sep < value) 
00491         {
00492           value = NULL;
00493         }
00494         else 
00495         {
00496           *value = '\0'; /* terminate name */
00497           value++;
00498         }
00499       }
00500       if (sep)
00501       {
00502         *sep = '\0'; /* terminate value */
00503         sep++;
00504       }
00505 
00506       printf("-w: %s\n", name);
00507 
00508       /* Write any number of params to device. */
00509       while (name != NULL && *name != '\0')
00510       {
00511         if (value)
00512         {
00513           if (writeParam(name, value))
00514           {
00515             fprintf(stderr, "Warning: Parameter %s already exists.\n", name);
00516             exitStat = 1;
00517           }
00518         }
00519         else
00520         {
00521           fprintf(stderr, "Warning: Parameter %s submitted without value.\n", name);
00522           exitStat = 1;
00523         }
00524         name = sep;
00525         if (name)
00526         {
00527           value = strchr(name, '=');
00528           sep = strchr(name, ':');
00529           if (value)
00530           {
00531             if (sep && sep < value)
00532             {
00533               value = NULL;
00534             }
00535             else
00536             {
00537               *value = '\0'; /* terminate name */
00538               value++;
00539             }
00540           }
00541           if (sep)
00542           {
00543             *sep = '\0'; /* terminate value */
00544             sep++;
00545           }
00546         }
00547       }
00548       argc--;
00549       argv++;
00550     }
00551     else
00552     {
00553       printUsage();
00554     }
00555   }
00556   if (useHTML)
00557   {
00558     printf(HTML_END);
00559   }
00560   closelog();
00561 
00562   if (setExitErr)
00563     return exitStat;
00564   return NO_ERROR;
00565 }
00566 
00567 
00568 /* Print helping message to user. */
00569 static void
00570 printUsage(void)
00571 {
00572   if (useHTML)
00573   {
00574     printf(usage);
00575   }
00576   else
00577   {
00578     fprintf(stderr, usage);
00579   }
00580   exit(1);
00581 }
00582 
00583 
00584 /* Print error message and exit. */
00585 static void
00586 die(const char *err)
00587 {
00588   if (useHTML)
00589   {
00590     printf("Error: %s\n", err);
00591     printf(HTML_END);
00592     exit(1);
00593   }
00594   else
00595   {
00596     fprintf(stderr, "Error: %s\n", err);
00597     exit(1);
00598   }
00599 }
00600 
00601 
00602 /* Write a parameter with the specified name and value.  */
00603 static int
00604 writeParam(const char *name, const char *value)
00605 {
00606   int offset;
00607   int f;
00608   int readerr;
00609 
00610   D(printf("writeParam: %s=%s\n", name, value));
00611 
00612   if (strlen(name) > MAX_PARAM_NAME_LEN)
00613   {
00614     syslog(LOG_ERR, "Parameter name too long! %m");
00615     die("Parameter name too long!\n");
00616   }
00617 
00618   /* See if it already exists. The reference to offset
00619   ** is set to the next position to store a param at.
00620   */
00621   readerr = readParam(name, 0, &offset);
00622   if (!readerr)
00623   {
00624     /* It already exists!  */
00625     return ERR_OTHER;
00626   }
00627 
00628   if ((f = open(dev, O_WRONLY )) == -1)
00629   {
00630     syslog(LOG_ERR, "Couldn't open bootblock device! %m");
00631     die("Couldn't open device!\n");
00632   }
00633 
00634   /* If the offset was at start of area, we need to write a magic.  */
00635 
00636   if (readerr == ERR_NO_MAGIC)
00637   {
00638     if (writeMagic(f, &offset) < 0)
00639     {
00640       close(f);
00641       die("Error writing magic!\n");
00642     }
00643   }
00644 
00645   if (writeParamAt(f, offset, name, value) < 0)
00646   {
00647     close(f);
00648     die("Error writing parameters!\n");
00649   }
00650   syslog(LOG_NOTICE, "Wrote new parameter: %s=%s\n", name, value);
00651   close(f);
00652   return NO_ERROR;
00653 }
00654 
00655 
00656 /* List the parameters */
00657 static void
00658 listParams(Toutput_type output_type)
00659 {
00660   int offset = FlashOffset;
00661   int f;
00662   char *parname;
00663   char *parvalue;
00664   int namelen;
00665   int valuelen;
00666   int totlen;
00667   unsigned long magic = 0;
00668 
00669   if ((f = open(dev, O_RDONLY)) == -1)
00670   {
00671     syslog(LOG_ERR, "Couldn't open bootblock device! %m");
00672     die("Couldn't open bootblock device!\n");
00673   }
00674 
00675   /* for nand flash, must skip bad blocks */
00676   if (nandFlash)
00677     skipBadBlocks(f, &offset);
00678 
00679   /* Check for correct magic.  */
00680 
00681   if (lseek(f, offset, SEEK_SET) < 0)
00682   {
00683     int err_saved = errno;
00684     
00685     perror("lseek");
00686     syslog(LOG_ERR, "lseek() failed. %s", strerror(err_saved));
00687     fprintf(stderr, "bootblocktool[%d]: seek failed.\n", getpid());
00688     close(f);
00689     return;
00690   }
00691 
00692   read(f, &magic, sizeof(magic));
00693 
00694   if (magic == EMPTYMAGIC)
00695   {
00696     /* Empty, probably not written yet.  */
00697     D(printf("EMPTYMAGIC!\n"));
00698     close(f);
00699     return;
00700   }
00701 
00702   if (magic != PARAMMAGIC)
00703   {
00704     syslog(LOG_ERR, "Wrong magic number found when trying to read parameter.");
00705     printf("ERROR: Wrong MAGIC for bootparams in listParams!\n");
00706     close(f);
00707     return;
00708   }
00709 
00710   /* OK magic, proceed...  */
00711 
00712   offset += nandFlash ? pageSize : sizeof(magic);
00713 
00714   /* Iterate through all parameters in the device, printing each one. */
00715   for (;;)
00716   {
00717     /* end of flash */
00718     if (offset >= FlashEnd)
00719     {
00720       close(f);
00721       return;
00722     }
00723 
00724     /* for nand flash, must skip bad blocks */
00725     if (nandFlash && BLOCK_START(offset, blockSize))
00726       skipBadBlocks(f, &offset);
00727 
00728     int ret = readParamAt(f, offset, &parname, &namelen,
00729                           &parvalue, &valuelen, &totlen);
00730     if (ret == ERR_END_OF_PARAMS)
00731     {
00732       /* Parameter not found. */
00733       close(f);
00734       return;
00735     }
00736     else if (ret)
00737     {
00738       close(f);
00739       printf("ERROR: Unknown error when reading bootblock in listParams!\n");
00740       return;
00741     }
00742     else
00743     {
00744       /* We found a parameter. */
00745       switch (output_type)
00746       {
00747        case NAMEVALUE:
00748         printf("%s=%s\n", parname, parvalue);
00749         break;
00750        case SCRIPT:
00751         printf("setenv %s \"%s\"\n", parname, parvalue);
00752         break;
00753       }
00754       free (parname);
00755       free (parvalue);
00756 
00757       /* for nandflash, round offset to nearest larger page */
00758       offset += nandFlash ? ROUND_UP(totlen, pageSize) : totlen; 
00759     }
00760   }
00761 }
00762 
00763 
00764 /* Search for the parameter named 'name'. Set the value reference to
00765 ** point to the value of it, which must be freed by the caller
00766 ** (when NO_ERROR is returned. When an error is returned, the
00767 ** value should not be freed). Value may also be 0 in which case 
00768 ** the reference is not set. If firstfree is non-zero, it is set to 
00769 ** the next free location in case the parameter is not found.
00770 */
00771 static int
00772 readParam(const char *name, char **value, int *firstfree)
00773 {
00774   int offset = FlashOffset;
00775   int f;
00776   char *parname;
00777   char *parvalue;
00778   int namelen;
00779   int valuelen;
00780   int totlen;
00781   unsigned long magic = 0;
00782   D(printf("readParam: '%s' \n", name));
00783   
00784   if ((f = open(dev, O_RDONLY)) == -1)
00785   {
00786     syslog(LOG_ERR, "Couldn't open bootblock device! %m");
00787     die("Couldn't open bootblock device!\n");
00788   }
00789 
00790   /* for nand flash, must skip bad blocks */
00791   if (nandFlash)
00792     skipBadBlocks(f, &offset);
00793 
00794   /* Check for correct magic.  */
00795 
00796   if (lseek(f, offset, SEEK_SET) < 0)
00797   {
00798     int err_saved = errno;
00799     
00800     perror("lseek");
00801     close(f);
00802     syslog(LOG_ERR, "lseek() failed. %s", strerror(err_saved));
00803     die("bootblocktoo: seek failed.\n");
00804   }
00805   read(f, &magic, sizeof(magic));
00806 
00807   if (magic == EMPTYMAGIC)
00808   {
00809     /* Empty.  Probably not written yet.  */
00810     close(f);
00811     *firstfree = offset;
00812     return ERR_NO_MAGIC;
00813   }
00814 
00815   if (magic != PARAMMAGIC)
00816   {
00817     close(f);
00818     syslog(LOG_ERR, "Wrong magic number found when trying to read parameter.");
00819     die("Wrong MAGIC for bootparams in readParam!\n");
00820   }
00821 
00822   /* ok magic, proceed */
00823 
00824   offset += nandFlash ? pageSize : sizeof(magic);
00825 
00826   /* Iterate through all parameters in the device, looking for a name
00827      match.  */
00828   for (;;)  /* Until found or failure. */
00829   {
00830     /* for nand flash, must skip bad blocks */
00831     if (nandFlash && BLOCK_START(offset, blockSize))
00832       skipBadBlocks(f, &offset);
00833 
00834     int ret = readParamAt(f, offset, &parname, &namelen,
00835                           &parvalue, &valuelen, &totlen);
00836     if (ret == ERR_END_OF_PARAMS)
00837     {
00838       /* Parameter not found. */
00839       close(f);
00840       *firstfree = offset;
00841       return ERR_OTHER;
00842     }
00843     else if (ret == ERR_OTHER)
00844     {
00845       close(f);
00846       die("Unknown error when reading bootblock in readParam!\n");
00847     }
00848     else if (!strcmp(parname, name))
00849     {
00850       /* We found the parameter. */
00851       free (parname);
00852       if (value)
00853         *value = parvalue; /* Must be freed by caller.  */
00854       else
00855         free (parvalue); /* caller not interested, so must free it here */
00856       close(f);
00857       return NO_ERROR;
00858     }
00859     else
00860     {
00861       free (parname);
00862       free (parvalue);
00863       /* for nandflash, round offset to nearest larger page */
00864       offset += nandFlash ? ROUND_UP(totlen, pageSize) : totlen;
00865     }
00866   }
00867 }
00868 
00869 
00870 /* Read a bootparam at the specified offset.
00871 ** Create strings and set lengths. Name and value
00872 ** references must be freed by the caller when NO_ERROR is returned.
00873 ** When an error is returned, no freeing is required or should be done.
00874 */
00875 static int
00876 readParamAt(int f, int offset, char **name, int *nameLen,
00877       char **value, int *valueLen, int *totlen)
00878 {
00879   unsigned int totallen;
00880   unsigned char buf[2];
00881   D(printf("readParamAt: %i\n", offset));
00882 
00883   /* Don't attempt to read beyond end of parameters */
00884   if (offset >= FlashEnd)
00885       return ERR_END_OF_PARAMS;
00886   
00887   /* Seek to the given offset.  */
00888   if (lseek(f, offset, SEEK_SET) < 0)
00889   {
00890     syslog(LOG_ERR, "Could not read parameter! lseek() failed! %m");
00891     D(printf("lseek failed\n"));
00892 
00893     return ERR_OTHER;
00894   }
00895 
00896   /* See the format specified in the README file.  */
00897   if (read(f, buf, 2) != 2)
00898   {
00899     return ERR_OTHER;
00900   }
00901   totallen = buf[0] + (buf[1] << 8);
00902   D(printf(" totallen: %i \n", totallen));
00903   if (totallen == 0xffff)
00904   {
00905     return ERR_END_OF_PARAMS;
00906   }
00907   if (read(f, buf, 1) != 1)
00908   {
00909     return ERR_OTHER;
00910   }
00911   *nameLen = (int)buf[0];
00912   D(printf(" nameLen: %i \n", *nameLen));
00913   /* Allocate space for the name.  Null-terminate it.  */
00914   if (!(*name = (char *)malloc(*nameLen + 1))) 
00915     return ERR_OTHER;
00916   if (read(f, *name, *nameLen) != *nameLen)
00917   {
00918     free (*name);
00919     return ERR_OTHER;
00920   }
00921   (*name)[*nameLen] = '\0';
00922   D(printf(" *name: %s \n", *name));
00923   *valueLen = totallen - 3 - *nameLen;
00924   /* Allocate space for the value.  Null-terminated.  */
00925   if (!(*value = (char *)malloc(*valueLen + 1)))
00926   {
00927     free(*name);
00928     return ERR_OTHER;
00929   }
00930 
00931   if (read(f, *value, *valueLen) != *valueLen)
00932   {
00933     free(*name);
00934     free(*value);
00935     return ERR_OTHER;
00936   }
00937   (*value)[*valueLen] = 0;
00938   *totlen = totallen;
00939   return 0;
00940 }
00941 
00942 
00943 /* I think this is pretty obvious. Write a parameter at the offset specified.
00944 ** See the README file for info on the format.
00945 */
00946 static int
00947 writeParamAt(int f, int offset, const char *name, const char *value)
00948 {
00949   int bufsize;
00950   unsigned char *buf;
00951   int valuelen;
00952   int namelen;
00953   int totlen;
00954   D(printf("writeParamAt: %i'%s'='%s' \n", offset, name, value));
00955   valuelen = strlen(value);
00956   namelen = strlen(name);
00957   totlen = 3 + namelen + valuelen;
00958 
00959   /* for nand flash, need to write in complete pages, so round up buffer
00960    * size to next complete page
00961    */
00962   bufsize = nandFlash ? ROUND_UP(totlen, pageSize) : totlen;
00963   D(printf("buffer size %d\n", bufsize));
00964 
00965   if (totlen >= MAX_RECORD_LEN || /* >= because 0xffff is the end marker */
00966       !(buf = (unsigned char *)malloc(bufsize)) ||
00967       offset + bufsize >= FlashEnd)
00968   {
00969     return ERR_OTHER;
00970   }
00971 
00972   /* Since we haven't implemented functionality for letting parameters
00973    * span bad blocks in nand flashes, we need to enforce a limitation
00974    * that all parameters must be in the same page.
00975    * Therefore, when adding a parameter, check that the parameter + 
00976    * end marker (in its own page) is still within the same block.
00977    */
00978   if (nandFlash) {
00979     if ((offset & ~(blockSize - 1)) != /* blockno << 14 of start of parameter */
00980         ((offset + bufsize) & ~(blockSize - 1))) /* blockno << 14 of next one */
00981     {
00982       D(printf("parameter won't fit!\n"));
00983       D(printf("offset = 0x%x, bufsize = 0x%x, "
00984                "offsetpage = 0x%x, offset+bufpage = 0x%x\n",
00985                offset, bufsize, offset & ~(blockSize -1), 
00986                (offset + bufsize) & ~(blockSize-1)));
00987       return ERR_OTHER;
00988     }
00989   }
00990 
00991   if (nandFlash)
00992     memset(buf, 0xff, bufsize);
00993 
00994   buf[0] = (totlen & 0x00ff) >> 0;
00995   buf[1] = (totlen & 0xff00) >> 8;
00996   buf[2] = (namelen & 0x00ff) >> 0;
00997   memcpy(buf + 3, name, namelen);
00998   memcpy(buf + 3 + namelen, value, valuelen);
00999 
01000   if (lseek(f, offset, SEEK_SET) < 0)
01001   {
01002     int err_saved = errno;
01003     
01004     D(perror("lseek");
01005       printf("lseek failed\n");
01006       );
01007     syslog(LOG_ERR, "Could not write parameter! lseek() failed! %s", strerror(err_saved));
01008     goto error;
01009   }
01010 
01011   /* If not the entire buf can be written in one chunk, then there is
01012      something fishy.  */
01013   if (write(f, buf, bufsize) != bufsize)
01014   {
01015     int err_saved = errno;
01016     
01017     D(perror("write ");
01018       printf("write failed\n"); 
01019       );
01020     syslog(LOG_ERR, "Could not write parameter! write() failed! %s", strerror(err_saved));
01021     goto error;
01022   }
01023 
01024   free(buf);
01025   return NO_ERROR;
01026 
01027  error:
01028   free(buf);
01029   return ERR_OTHER;
01030 }
01031 
01032 
01033 /* Write PARAMMAGIC at *offset; update *offset to reflect position to
01034  * write first parameter at.
01035  */
01036 static int
01037 writeMagic(int file, int *offset)
01038 {
01039   int bufsize;
01040   unsigned char *buf;
01041   unsigned long magic = PARAMMAGIC;
01042 
01043   D(printf("writeMagic at %i \n", *offset));
01044 
01045   bufsize = nandFlash ? pageSize : sizeof(magic);
01046   if (!(buf = (unsigned char *)malloc(bufsize)))
01047   {
01048     return ERR_OTHER;
01049   }
01050 
01051   if (nandFlash)
01052     memset(buf, 0xff, bufsize);
01053 
01054   memcpy(buf, &magic, sizeof(magic));
01055 
01056   if (lseek(file, *offset, SEEK_SET) < 0)
01057   {
01058     int err_saved = errno;
01059     
01060     D(perror("lseek");
01061       printf("lseek failed\n");
01062       );
01063     syslog(LOG_ERR, "Could not write magic number! lseek() failed! %s", strerror(err_saved));
01064     goto error;
01065   }
01066   /* If not the entire buf can be written in one chunk, then there is
01067      something fishy.  */
01068   if (write(file, buf, bufsize) != bufsize)
01069   {
01070     int err_saved = errno;
01071 
01072     D(perror("write"); 
01073       printf("write failed\n"););
01074     syslog(LOG_ERR, "Could not write magic number! write() failed! %s", strerror(err_saved));
01075     goto error;
01076   }
01077 
01078   (*offset) += bufsize;
01079 
01080   free(buf);
01081 
01082   return NO_ERROR;
01083 
01084  error:
01085   free(buf);
01086   return ERR_OTHER;
01087 }
01088 
01089 
01090 /* Obtain chip parameters from mtd layer, set nandFlash, blockSize and pageSize.
01091  * Return 0 if all ok, -1 if couldn't get parameters.
01092  * die if running on system with NAND flash but not proper NAND support in
01093  * kernel mtd layer (e.g. Linux 2.4 with NAND flash; not likely in 
01094  * practice).
01095  */
01096 static int
01097 getChipParams(void)
01098 {
01099   int fd;
01100   struct mtd_info_user mtdInfo;
01101 
01102   if ((fd = open(dev, O_RDONLY)) < 0)
01103   {
01104     syslog(LOG_ERR, "Couldn't open bootblock device! %m");
01105     die("Couldn't open bootblock device!\n");
01106   }
01107 
01108   /* read chip parameters */
01109 
01110 #if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
01111 
01112   if ((ioctl(fd, MEMGETINFO, &mtdInfo)) < 0) 
01113   {
01114     close(fd);
01115     syslog(LOG_ERR, "Couldn't get chip parameters! %m");
01116     die("Couldn't get chip parameters!\n");
01117   }
01118 
01119   nandFlash = (mtdInfo.type == MTD_NANDFLASH); /* 1 or 0 */
01120   blockSize = mtdInfo.erasesize; /* eg. 16k for 32Mbyte nand flash */
01121 #if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 18)
01122   pageSize = mtdInfo.writesize; /* eg. 512 for 32Mbyte nand flash */
01123 #else
01124   pageSize = mtdInfo.oobblock; /* eg. 512 for 32Mbyte nand flash */
01125 #endif
01126 
01127 #else /* no NAND support in 2.4.x */
01128 
01129   nandFlash = blockSize = pageSize = 0;
01130 
01131 #endif
01132 
01133   D(printf("Flash type %s, blocksize %d, pagesize %d\n",
01134     nandFlash ? "NAND" : "NOR", blockSize, pageSize));
01135 
01136 #if !defined(MEMGETBADBLOCK)
01137   if (nandFlash)
01138   {
01139     syslog(LOG_ERR, "NAND flash bad block detection "
01140                     "not supported in this kernel version! %m");
01141     die("NAND flash bad block detection not supported in this kernel version\n");
01142   }
01143 #endif
01144 
01145   close(fd);
01146 
01147   return 0;
01148 }
01149 
01150 
01151 /* Update *offset to refer to next available good block.
01152  * Return 0 if block could be found, 1 if we hit FlashEnd.
01153  */
01154 static void
01155 skipBadBlocks(int fd, int *offset)
01156 {
01157 #if defined(MEMGETBADBLOCK)
01158   int blockbad = 1;
01159 
01160   loff_t loffset = *offset;
01161 
01162   while (blockbad && loffset < FlashEnd)
01163   {
01164     if ((blockbad = ioctl(fd, MEMGETBADBLOCK, &loffset)) < 0)
01165     {
01166       close(fd);
01167       syslog(LOG_ERR, "Couldn't determine block status! %m");
01168       die("Couldn't determine block status!\n");
01169     }
01170     if (blockbad)
01171       loffset += blockSize;
01172   }
01173 
01174   *offset = loffset;
01175   if (loffset >= FlashEnd)
01176   {
01177     close(fd);
01178     syslog(LOG_ERR, "Ran out of good blocks!");
01179     die("Ran out of good blocks!\n");
01180   }
01181 
01182 #else
01183   /* not much we can do. The fact that bad blocks are not handled properly
01184    * will have been noted when the chip parameters were detected and the 
01185    * program terminated accordingly.
01186    */
01187 #endif
01188 }
01189 
01190 
01191 /* Set program internal flash memory parameters (start and end)
01192  * from chip parameters. 
01193  * Return 0 if all is well, -1 if couldn't obtain chip parameters.
01194  */
01195 static int
01196 setFlashParams(void)
01197 {
01198 
01199 #if !defined(USE_FWINFO_AREA) || NAND_NOR_COMPATIBILITY_MODE
01200 
01201 /* same addresses as ordinarily used for NOR flash. Only useful for testing. */
01202 /* Also includes this weird backup stuff. So far. */
01203   if (PARAMMAGIC == PARAMMAGIC_PRIMARY) {
01204     FlashOffset = 0xc000;
01205     FlashEnd = 0x10000;
01206   } else {
01207     FlashOffset = 0x10000;
01208     FlashEnd = 0x14000; /* i.e. one block on a 16k-block flash */
01209   }
01210 
01211 #else
01212 
01213   struct fwinfo fwinfo;
01214 
01215   if (read_flash_fwinfo(dev, &fwinfo) < 0)
01216       return -1;
01217 
01218   FlashOffset = fwinfo.bootblkpar_flash_addr;
01219   FlashEnd = fwinfo.bootblkpar_flash_end;
01220 
01221 #endif
01222 
01223   if (getChipParams() < 0)
01224     return -1;
01225 
01226   return 0;
01227 }
01228 
01229 /****************** END OF FILE bootblocktool.c *****************************/

Generated on Fri Nov 28 00:06:21 2008 for elphel by  doxygen 1.5.1