chknvm.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /*====================================================================*
  2. *
  3. * Copyright (c) 2013 Qualcomm Atheros, Inc.
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or
  8. * without modification, are permitted (subject to the limitations
  9. * in the disclaimer below) provided that the following conditions
  10. * are met:
  11. *
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * * Redistributions in binary form must reproduce the above
  16. * copyright notice, this list of conditions and the following
  17. * disclaimer in the documentation and/or other materials
  18. * provided with the distribution.
  19. *
  20. * * Neither the name of Qualcomm Atheros nor the names of
  21. * its contributors may be used to endorse or promote products
  22. * derived from this software without specific prior written
  23. * permission.
  24. *
  25. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
  26. * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
  27. * COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  28. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  29. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  31. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  32. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  33. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  36. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  37. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  38. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39. *
  40. *--------------------------------------------------------------------*/
  41. /*====================================================================*"
  42. *
  43. * chknvm.c
  44. *
  45. *
  46. * Contributor(s):
  47. * Charles Maier
  48. *
  49. *--------------------------------------------------------------------*/
  50. /*====================================================================*
  51. * system header files;
  52. *--------------------------------------------------------------------*/
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <unistd.h>
  56. #include <memory.h>
  57. #include <fcntl.h>
  58. #include <errno.h>
  59. /*====================================================================*
  60. * custom header files;
  61. *--------------------------------------------------------------------*/
  62. #include "../tools/getoptv.h"
  63. #include "../tools/memory.h"
  64. #include "../tools/flags.h"
  65. #include "../tools/error.h"
  66. #include "../tools/files.h"
  67. #include "../ram/sdram.h"
  68. #include "../nvm/nvm.h"
  69. /*====================================================================*
  70. * custom source files;
  71. *--------------------------------------------------------------------*/
  72. #ifndef MAKEFILE
  73. #include "../tools/getoptv.c"
  74. #include "../tools/putoptv.c"
  75. #include "../tools/version.c"
  76. #include "../tools/checksum32.c"
  77. #include "../tools/fdchecksum32.c"
  78. #include "../tools/strfbits.c"
  79. #include "../tools/error.c"
  80. #endif
  81. #ifndef MAKEFILE
  82. #include "../ram/sdrampeek.c"
  83. #endif
  84. #ifndef MAKEFILE
  85. #include "../nvm/nvm.c"
  86. #include "../nvm/nvmpeek.c"
  87. #include "../nvm/nvmpeek1.c"
  88. #include "../nvm/nvmpeek2.c"
  89. #include "../nvm/manifest.c"
  90. #include "../nvm/fdmanifest.c"
  91. #endif
  92. /*====================================================================*
  93. * program constants;
  94. *--------------------------------------------------------------------*/
  95. #define HARDWARE 0
  96. #define SOFTWARE 1
  97. #define VER 2
  98. #define REV 3
  99. #define BUILD 6
  100. #define DATE 7
  101. /*====================================================================*
  102. *
  103. * unsigned string2vector (char ** vector, length, char * string, char c);
  104. *
  105. * convert string to a vector and return vector count; split string
  106. * on characer (c);
  107. *
  108. *
  109. * Contributor(s):
  110. * Charles Maier
  111. *
  112. *--------------------------------------------------------------------*/
  113. static unsigned string2vector (char ** vector, char * string, char c)
  114. {
  115. char ** origin = vector;
  116. for (*vector++ = string; *string; string++)
  117. {
  118. if (*string == c)
  119. {
  120. *string++ = (char)(0);
  121. *vector++ = string--;
  122. }
  123. }
  124. *vector = (char *)(0);
  125. return ((unsigned)(vector - origin));
  126. }
  127. /*====================================================================*
  128. *
  129. * void firmware (signed fd, char const * filename, unsigned module, unsigned offset, flag_t flags);
  130. *
  131. *
  132. * Contributor(s):
  133. * Charles Maier
  134. *
  135. *--------------------------------------------------------------------*/
  136. static void firmware (signed fd, char const * filename, unsigned module, unsigned offset, flag_t flags)
  137. {
  138. char memory [512];
  139. read (fd, memory, sizeof (memory));
  140. lseek (fd, (off_t)(0) - sizeof (memory), SEEK_CUR);
  141. if (_anyset (flags, NVM_FIRMWARE))
  142. {
  143. if ((*memory > 0x20) && (*memory < 0x7F))
  144. {
  145. printf ("%s (%d) %s\n", filename, module, memory);
  146. }
  147. else
  148. {
  149. printf ("%s (%d) %s\n", filename, module, memory + offset);
  150. }
  151. }
  152. if (_anyset (flags, NVM_IDENTITY))
  153. {
  154. char * vector [16];
  155. char buffer [256];
  156. if ((* memory > 0x20) && (* memory < 0x7f))
  157. {
  158. strncpy (buffer, memory, sizeof (buffer));
  159. }
  160. else
  161. {
  162. strncpy (buffer, memory + offset, sizeof (buffer));
  163. }
  164. string2vector (vector, buffer, '-');
  165. printf ("%s ", vector [HARDWARE]);
  166. printf ("%04d ", atoi (vector [BUILD]));
  167. printf ("%s ", vector [DATE]);
  168. printf ("%s.", vector [VER]);
  169. printf ("%s ", vector [REV]);
  170. printf ("%s (%d)\n", filename, module);
  171. return;
  172. }
  173. return;
  174. }
  175. /*====================================================================*
  176. *
  177. * signed nvmchain1 (signed fd, char const * filename, flag_t flags);
  178. *
  179. * validate a legcy PLC firmware file; return 0 on success or -1 on
  180. * error;
  181. *
  182. * keep as little information as possible in memory; this slows
  183. * validation but minimizes the resources needed at runtime so
  184. * that resource requirements do not grow with file size;
  185. *
  186. * the checksum of the entire header, including header checksum, is
  187. * always 0 for valid headers; similarly, the checksum of the module
  188. * and module checksum is always 0 for valid modules;
  189. *
  190. *
  191. * Contributor(s):
  192. * Charles Maier
  193. *
  194. *--------------------------------------------------------------------*/
  195. static signed nvmchain1 (signed fd, char const * filename, flag_t flags)
  196. {
  197. struct nvm_header1 nvm_header;
  198. struct config_ram config_ram;
  199. unsigned module = 0;
  200. do
  201. {
  202. if (read (fd, &nvm_header, sizeof (nvm_header)) != sizeof (nvm_header))
  203. {
  204. if (_allclr (flags, NVM_SILENCE))
  205. {
  206. error (0, errno, NVM_HDR_CANTREAD, filename, module);
  207. }
  208. return (-1);
  209. }
  210. if (LE32TOH (nvm_header.HEADERVERSION) != 0x60000000)
  211. {
  212. if (_allclr (flags, NVM_SILENCE))
  213. {
  214. error (0, errno, NVM_HDR_VERSION, filename, module);
  215. }
  216. return (-1);
  217. }
  218. if (checksum32 (&nvm_header, sizeof (nvm_header), 0))
  219. {
  220. if (_allclr (flags, NVM_SILENCE))
  221. {
  222. error (0, errno, NVM_HDR_CHECKSUM, filename, module);
  223. }
  224. return (-1);
  225. }
  226. if (_anyset (flags, NVM_VERBOSE))
  227. {
  228. printf ("------- %s (%d) -------\n", filename, module);
  229. nvmpeek1 (&nvm_header);
  230. }
  231. if (nvm_header.HEADERMINORVERSION)
  232. {
  233. if (LE32TOH (nvm_header.IMAGETYPE) == NVM_IMAGE_CONFIG_SYNOPSIS)
  234. {
  235. if (_anyset (flags, NVM_SDRAM))
  236. {
  237. printf ("------- %s (%d) -------\n", filename, module);
  238. read (fd, &config_ram, sizeof (config_ram));
  239. lseek (fd, (off_t)(0) - sizeof (config_ram), SEEK_CUR);
  240. sdrampeek (&config_ram);
  241. }
  242. }
  243. else if (LE32TOH (nvm_header.IMAGETYPE) == NVM_IMAGE_FIRMWARE)
  244. {
  245. firmware (fd, filename, module, 0x70, flags);
  246. }
  247. }
  248. else if (!module)
  249. {
  250. if (_anyset (flags, NVM_SDRAM))
  251. {
  252. printf ("------- %s (%d) -------\n", filename, module);
  253. read (fd, &config_ram, sizeof (config_ram));
  254. lseek (fd, (off_t)(0) - sizeof (config_ram), SEEK_CUR);
  255. sdrampeek (&config_ram);
  256. }
  257. }
  258. else if (!nvm_header.NEXTHEADER)
  259. {
  260. firmware (fd, filename, module, 0x70, flags);
  261. }
  262. if (fdchecksum32 (fd, LE32TOH (nvm_header.IMAGELENGTH), nvm_header.IMAGECHECKSUM))
  263. {
  264. if (_allclr (flags, NVM_SILENCE))
  265. {
  266. error (0, errno, NVM_IMG_CHECKSUM, filename, module);
  267. }
  268. return (-1);
  269. }
  270. module++;
  271. }
  272. while (nvm_header.NEXTHEADER);
  273. if (lseek (fd, 0, SEEK_CUR) != lseek (fd, 0, SEEK_END))
  274. {
  275. if (_allclr (flags, NVM_SILENCE))
  276. {
  277. error (0, errno, NVM_HDR_LINK, filename, module);
  278. }
  279. return (-1);
  280. }
  281. return (0);
  282. }
  283. /*====================================================================*
  284. *
  285. * signed nvmchain2 (signed fd, char const * filename, flag_t flags);
  286. *
  287. * validate a PLC image file; return 0 on success or -1 on error;
  288. *
  289. * keep as little information as possible in memory; this slows
  290. * validation but minimizes the resources needed at runtime so
  291. * that resource requirements do not grow with file size;
  292. *
  293. * the checksum of the entire header, including header checksum, is
  294. * always 0 for valid headers; similarly, the checksum of the module
  295. * and module checksum is always 0 for valid modules;
  296. *
  297. *
  298. * Contributor(s):
  299. * Charles Maier
  300. *
  301. *--------------------------------------------------------------------*/
  302. static signed nvmchain2 (signed fd, char const * filename, flag_t flags)
  303. {
  304. struct nvm_header2 nvm_header;
  305. unsigned module = 0;
  306. uint32_t origin = ~0;
  307. uint32_t offset = 0;
  308. do
  309. {
  310. if (read (fd, &nvm_header, sizeof (nvm_header)) != sizeof (nvm_header))
  311. {
  312. if (_allclr (flags, NVM_SILENCE))
  313. {
  314. error (0, errno, NVM_HDR_CANTREAD, filename, module);
  315. }
  316. return (-1);
  317. }
  318. if (LE16TOH (nvm_header.MajorVersion) != 1)
  319. {
  320. if (_allclr (flags, NVM_SILENCE))
  321. {
  322. error (0, errno, NVM_HDR_VERSION, filename, module);
  323. }
  324. return (-1);
  325. }
  326. if (LE16TOH (nvm_header.MinorVersion) != 1)
  327. {
  328. if (_allclr (flags, NVM_SILENCE))
  329. {
  330. error (0, errno, NVM_HDR_VERSION, filename, module);
  331. }
  332. return (-1);
  333. }
  334. if (checksum32 (&nvm_header, sizeof (nvm_header), 0))
  335. {
  336. if (_allclr (flags, NVM_SILENCE))
  337. {
  338. error (0, errno, NVM_HDR_CHECKSUM, filename, module);
  339. }
  340. return (-1);
  341. }
  342. if (LE32TOH (nvm_header.PrevHeader) != origin)
  343. {
  344. if (_allclr (flags, NVM_SILENCE))
  345. {
  346. error (0, errno, NVM_HDR_LINK, filename, module);
  347. }
  348. return (-1);
  349. }
  350. if (_anyset (flags, NVM_VERBOSE))
  351. {
  352. printf ("------- %s (%d) -------\n", filename, module);
  353. nvmpeek2 (&nvm_header);
  354. }
  355. if (LE32TOH (nvm_header.ImageType) == NVM_IMAGE_MANIFEST)
  356. {
  357. if (_anyset (flags, NVM_MANIFEST))
  358. {
  359. fdmanifest (fd, filename, &nvm_header, module);
  360. return (0);
  361. }
  362. }
  363. if (fdchecksum32 (fd, LE32TOH (nvm_header.ImageLength), nvm_header.ImageChecksum))
  364. {
  365. if (_allclr (flags, NVM_SILENCE))
  366. {
  367. error (0, errno, NVM_IMG_CHECKSUM, filename, module);
  368. }
  369. return (-1);
  370. }
  371. origin = offset;
  372. offset = LE32TOH (nvm_header.NextHeader);
  373. module++;
  374. }
  375. while (~nvm_header.NextHeader);
  376. if (lseek (fd, 0, SEEK_CUR) != lseek (fd, 0, SEEK_END))
  377. {
  378. if (_allclr (flags, NVM_SILENCE))
  379. {
  380. error (0, errno, NVM_HDR_LINK, filename, module);
  381. }
  382. return (-1);
  383. }
  384. return (0);
  385. }
  386. /*====================================================================*
  387. *
  388. * signed chknvm (char const * filename, flag_t flags);
  389. *
  390. * validate a PLC firmware module file; keep as little information
  391. * as possible in memory; this slows validation but minimizes the
  392. * resources needed at runtime; resource requirements do not grow
  393. * with file size;
  394. *
  395. * determine file format based on module header version then rewind
  396. * the file and call the appropriate chknvm;
  397. *
  398. *
  399. * Contributor(s):
  400. * Charles Maier
  401. *
  402. *--------------------------------------------------------------------*/
  403. static signed chknvm (char const * filename, flag_t flags)
  404. {
  405. uint32_t version;
  406. signed status;
  407. signed fd;
  408. if ((fd = open (filename, O_BINARY|O_RDONLY)) == -1)
  409. {
  410. if (_allclr (flags, NVM_SILENCE))
  411. {
  412. error (0, errno, FILE_CANTOPEN, filename);
  413. }
  414. return (-1);
  415. }
  416. if (read (fd, &version, sizeof (version)) != sizeof (version))
  417. {
  418. if (_allclr (flags, NVM_SILENCE))
  419. {
  420. error (0, errno, FILE_CANTREAD, filename);
  421. }
  422. return (-1);
  423. }
  424. if (lseek (fd, 0, SEEK_SET))
  425. {
  426. if (_allclr (flags, NVM_SILENCE))
  427. {
  428. error (0, errno, FILE_CANTHOME, filename);
  429. }
  430. return (-1);
  431. }
  432. if (LE32TOH (version) == 0x60000000)
  433. {
  434. status = nvmchain1 (fd, filename, flags);
  435. }
  436. else
  437. {
  438. status = nvmchain2 (fd, filename, flags);
  439. }
  440. close (fd);
  441. return (status);
  442. }
  443. /*====================================================================*
  444. *
  445. * int main (int argc, char const * argv []);
  446. *
  447. * validate a PLC firmware image file; keep as little information
  448. * as possible in memory; this slows validation but minimizes the
  449. * resources needed at runtime; resource requirements do not grow
  450. * with file size;
  451. *
  452. *
  453. * Contributor(s):
  454. * Charles Maier
  455. *
  456. *--------------------------------------------------------------------*/
  457. int main (int argc, char const * argv [])
  458. {
  459. static char const * optv [] =
  460. {
  461. "imqrsv",
  462. "file [file] [...]",
  463. "Qualcomm Atheros PLC Image File Validator",
  464. "i\tprint firmware identity string",
  465. "m\tdisplay manifest",
  466. "q\tsuppress messages",
  467. "r\tprint firmware revision string",
  468. "s\tprint SDRAM configuration blocks",
  469. "v\tverbose messages",
  470. (char const *) (0)
  471. };
  472. signed state = 0;
  473. flag_t flags = (flag_t)(0);
  474. signed c;
  475. optind = 1;
  476. while ((c = getoptv (argc, argv, optv)) != -1)
  477. {
  478. switch ((char) (c))
  479. {
  480. case 'i':
  481. _setbits (flags, NVM_IDENTITY);
  482. break;
  483. case 'r':
  484. _setbits (flags, NVM_FIRMWARE);
  485. break;
  486. case 'm':
  487. _setbits (flags, NVM_MANIFEST);
  488. break;
  489. case 's':
  490. _setbits (flags, NVM_SDRAM);
  491. break;
  492. case 'q':
  493. _setbits (flags, NVM_SILENCE);
  494. break;
  495. case 'v':
  496. _setbits (flags, NVM_VERBOSE);
  497. break;
  498. default:
  499. break;
  500. }
  501. }
  502. argc -= optind;
  503. argv += optind;
  504. while ((argc) && (* argv))
  505. {
  506. if (chknvm (* argv, flags))
  507. {
  508. state = 1;
  509. }
  510. else if (_allclr (flags, (NVM_VERBOSE|NVM_SILENCE|NVM_MANIFEST|NVM_FIRMWARE|NVM_IDENTITY|NVM_SDRAM)))
  511. {
  512. printf ("file %s looks good\n", * argv);
  513. }
  514. argc--;
  515. argv++;
  516. }
  517. return (state);
  518. }