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

Generated on Thu Aug 7 16:18:58 2008 for elphel by  doxygen 1.5.1