CPLFirmware.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /*====================================================================*
  2. *
  3. * Copyright (c) 2013 Qualcomm Atheros, Inc.
  4. *
  5. * All rights reserved.
  6. *
  7. *====================================================================*/
  8. /*====================================================================*
  9. *
  10. * CPLFirmware.cpp - CPLFirmware class definition;
  11. *
  12. * read/write a parameter block image from/to a device/file;
  13. *
  14. * Contributor(s):
  15. * Charles Maier <charles.maier@intellon.com>
  16. *
  17. *--------------------------------------------------------------------*/
  18. #ifndef CPLFIRMWARE_SOURCE
  19. #define CPLFIRMWARE_SOURCE
  20. /*====================================================================*
  21. * system header files;
  22. *--------------------------------------------------------------------*/
  23. #include <cstring>
  24. #include <fstream>
  25. /*====================================================================*
  26. * custom header files;
  27. *--------------------------------------------------------------------*/
  28. #include "../classes/CPLFirmware.hpp"
  29. #include "../classes/ohomeplug.hpp"
  30. #include "../classes/omemory.hpp"
  31. #include "../classes/oerror.hpp"
  32. #include "../tools/endian.h"
  33. /*====================================================================*
  34. *
  35. * void * Data () const;
  36. *
  37. * return firmware image sequence address as a void pointer; this
  38. * property can be used to perform image sequence operations that
  39. * have not been implemented by this class;
  40. *
  41. *--------------------------------------------------------------------*/
  42. void * CPLFirmware::Data () const
  43. {
  44. return ((void *)(this->mbuffer));
  45. }
  46. /*====================================================================*
  47. *
  48. * size_t Size () const;
  49. *
  50. * return firmware image sequence extent (length) in bytes;
  51. *
  52. *--------------------------------------------------------------------*/
  53. size_t CPLFirmware::Size () const
  54. {
  55. return (this->mextent);
  56. }
  57. /*====================================================================*
  58. *
  59. * bool IsValid () const;
  60. *
  61. * return true of the firmware image sequence is valid; check the
  62. *
  63. * this method may be expanded to include other parameter block
  64. * validity tests;
  65. *
  66. *--------------------------------------------------------------------*/
  67. bool CPLFirmware::IsValid () const
  68. {
  69. CPLFirmware::Header const * header;
  70. byte const * offset = (byte const *)(this->mbuffer);
  71. signed extent = this->mextent;
  72. signed image = 0;
  73. if ((!this->mbuffer) || (!this->mextent))
  74. {
  75. // oerror::error (0, ECANCELED, "No Firmware Image Available");
  76. return (false);
  77. }
  78. do
  79. {
  80. std::cout << "start " << image << std::endl;
  81. header = (CPLFirmware::Header const *)(offset);
  82. #if 1
  83. CPLFirmware::Peek (header);
  84. #endif
  85. if (LE32TOH (header->HEADERVERSION) != NVM_HEADER_VERSION)
  86. {
  87. oerror::error (1, 0, "Bad header version");
  88. return (false);
  89. }
  90. if (omemory::checksum32 (header, sizeof (CPLFirmware::Header), 0))
  91. {
  92. oerror::error (1, 0, "Bad header checksum");
  93. return (false);
  94. }
  95. offset += sizeof (CPLFirmware::Header);
  96. extent -= sizeof (CPLFirmware::Header);
  97. if (omemory::checksum32 (offset, LE32TOH (header->IMAGELENGTH), header->IMAGECHECKSUM))
  98. {
  99. oerror::error (1, 0, "Bad image checksum");
  100. return (false);
  101. }
  102. offset += header->IMAGELENGTH;
  103. extent -= header->IMAGELENGTH;
  104. image++;
  105. std::cout << "end " << image << std::endl;
  106. }
  107. while (header->NEXTHEADER);
  108. std::cout << "exit" << std::endl;
  109. return (!extent);
  110. }
  111. /*====================================================================*
  112. *
  113. * signed CPLFirmware::Read (char const * filename);
  114. *
  115. * read firmware image sequence from the named file;
  116. *
  117. *--------------------------------------------------------------------*/
  118. signed CPLFirmware::Read (char const * filename)
  119. {
  120. if (this->mbuffer)
  121. {
  122. delete [] this->mbuffer;
  123. }
  124. this->mextent = 0;
  125. if ((filename) && (*filename))
  126. {
  127. std::ifstream stream;
  128. stream.open (filename, std::ios::binary);
  129. if (stream.good ())
  130. {
  131. stream.seekg (0, std::ios::end);
  132. this->mextent = stream.tellg ();
  133. stream.seekg (0, std::ios::beg);
  134. this->mbuffer = new uint8_t [this->mextent];
  135. stream.read ((char *)(this->mbuffer), this->mextent);
  136. }
  137. stream.close ();
  138. }
  139. return (0);
  140. }
  141. /*====================================================================*
  142. *
  143. * signed Write (char const * filename);
  144. *
  145. * write firmware image sequence to the named file;
  146. *
  147. *--------------------------------------------------------------------*/
  148. signed CPLFirmware::Write (char const * filename)
  149. {
  150. std::ofstream stream;
  151. stream.open (filename, std::ios::binary);
  152. if (stream.good ())
  153. {
  154. stream.write ((char *)(this->mbuffer), this->mextent);
  155. }
  156. stream.close ();
  157. return (0);
  158. }
  159. /*====================================================================*
  160. *
  161. * signed Read (CPLCHannel * channel)
  162. *
  163. * read a firmware image sequence from the local powerline device
  164. * into memory using as many VS_RD_MOD messages as needed;
  165. *
  166. * return 0 on success or -1 on failure;
  167. *
  168. *--------------------------------------------------------------------*/
  169. #if 0
  170. signed CPLFirmware::Read (CPLChannel * channel)
  171. {
  172. ointellon intellon;
  173. uint8_t message [ETHER_MAX_LEN];
  174. #ifndef __GNUC__
  175. #pragma pack (push,1)
  176. #endif
  177. struct __packed vs_rd_mod_request
  178. {
  179. struct header_eth ethernet;
  180. struct header_int intellon;
  181. uint8_t MODULEID;
  182. uint8_t MACCESS;
  183. uint16_t MLENGTH;
  184. uint32_t MOFFSET;
  185. uint8_t MSECRET [16];
  186. }
  187. * request = (struct vs_rd_mod_request *) (message);
  188. struct __packed vs_rd_mod_confirm
  189. {
  190. struct header_eth ethernet;
  191. struct header_int intellon;
  192. uint8_t MSTATUS;
  193. uint8_t RES [3];
  194. uint8_t MODULEID;
  195. uint8_t RESERVED;
  196. uint16_t MLENGTH;
  197. uint32_t MOFFSET;
  198. uint32_t CHKSUM;
  199. uint8_t BUFFER [INT6K_BLOCKSIZE];
  200. }
  201. * confirm = (struct vs_rd_mod_confirm *) (message);
  202. #ifndef __GNUC__
  203. #pragma pack (pop)
  204. #endif
  205. uint16_t extent = 0;
  206. uint16_t length = oINTELLON_BLOCKSIZE;
  207. uint32_t offset = 0;
  208. intellon.ImportPeerAddress (channel->PeerAddress ());
  209. intellon.ImportHostAddress (channel->HostAddress ());
  210. intellon.SetMessageType (VS_RD_MOD | MMTYPE_REQ);
  211. do
  212. {
  213. std::memset (message, 0, sizeof (message));
  214. request = (struct vs_rd_mod_request *)(intellon.ExportHeader (message));
  215. confirm = (struct vs_rd_mod_confirm *)(request);
  216. request->MODULEID = VS_MODULE_MAC;
  217. request->MLENGTH = HTOLE16 (length);
  218. request->MOFFSET = HTOLE32 (offset);
  219. if (channel->SendMessage (message, ETHER_MIN_LEN) <= 0)
  220. {
  221. oerror::error (0, ECANCELED, CPLCHANNEL_CANTSEND);
  222. return (-1);
  223. }
  224. if (channel->ReadMessage (message, sizeof (message)) <= 0)
  225. {
  226. oerror::error (0, ECANCELED, CPLCHANNEL_CANTREAD);
  227. return (-1);
  228. }
  229. if (confirm->MSTATUS)
  230. {
  231. oerror::error (0, ECANCELED, CPLCHANNEL_WONTDOIT);
  232. return (-1);
  233. }
  234. #if 1
  235. if (LE16TOH (confirm->MLENGTH) != length)
  236. {
  237. oerror::error (0, ECANCELED, oINTELLON_BAD_LENGTH);
  238. return (-1);
  239. }
  240. if (LE32TOH (confirm->MOFFSET) != offset)
  241. {
  242. oerror::error (0, ECANCELED, oINTELLON_BAD_LENGTH);
  243. return (-1);
  244. }
  245. #else
  246. if (LE16TOH (confirm->MLENGTH) != length)
  247. {
  248. oerror::error (0, EIO, oINTELLON_BAD_LENGTH);
  249. this->mlength = INT6K_BLOCKSIZE;
  250. this->moffset = 0;
  251. continue;
  252. }
  253. if (LE32TOH (confirm->MOFFSET) != this->moffset)
  254. {
  255. oerror::error (0, EIO, oINTELLON_BAD_OFFSET);
  256. this->mlength = INT6K_BLOCKSIZE;
  257. this->moffset = 0;
  258. continue;
  259. }
  260. #endif
  261. length = LE16TOH (confirm->MLENGTH);
  262. offset = LE32TOH (confirm->MOFFSET);
  263. if (omemory::checksum32 (confirm->MBUFFER, length, confirm->MCHKSUM))
  264. {
  265. oerror::error (0, ECANCELED, "Bad Message Checksum");
  266. return (-1);
  267. }
  268. if (offset == extent)
  269. {
  270. CPLFirmware::Header * header = (CPLFirmware::Header *)(confirm->BUFFER);
  271. if (checksum_32 (header, sizeof (CPLFirmware::Header), 0))
  272. {
  273. oerror::error (0, ECANCELED, "Bad Header Checksum");
  274. return (-1);
  275. }
  276. if (header_nvm->HEADERVERSION != NVM_HEADER_VERSION)
  277. {
  278. oerror::error (0, ECANCELED, "Bad Header Version");
  279. return (-1);
  280. }
  281. extent += sizeof (CPLFirmware::Header);
  282. extent += LE32TOH (header_nvm->IMAGELENGTH);
  283. header = LE16TOH (header_nvm->NEXTHEADER);
  284. }
  285. if ((offset + length) > extent)
  286. {
  287. length = extent - offset;
  288. }
  289. std::memcpy (this->mbuffer + offset, confirm->MBUFFER, length);
  290. offset += length;
  291. extent -= length;
  292. }
  293. while ((header) || (offset < extent));
  294. return (0);
  295. }
  296. #endif
  297. /*====================================================================*
  298. *
  299. * signed Write (CPLChannel * channel);
  300. *
  301. * write the firmware image sequence from memory to any powerline
  302. * device using as many VS_WR_MOD messages as needed;
  303. *
  304. * the runtime firmware must be running for this to work;
  305. *
  306. * return 0 on success or -1 on failure;
  307. *
  308. *--------------------------------------------------------------------*/
  309. signed CPLFirmware::Write (CPLChannel * channel)
  310. {
  311. ointellon intellon;
  312. uint8_t message [ETHER_MAX_LEN];
  313. #ifndef __GNUC__
  314. #pragma pack (push,1)
  315. #endif
  316. struct __packed vs_wr_mod_request
  317. {
  318. uint8_t MODULEID;
  319. uint8_t RESERVED;
  320. uint16_t MLENGTH;
  321. uint32_t MOFFSET;
  322. uint32_t MCHKSUM;
  323. uint8_t MBUFFER [oINTELLON_BLOCKSIZE];
  324. }
  325. * request;
  326. struct __packed vs_wr_mod_confirm
  327. {
  328. uint8_t MSTATUS;
  329. uint8_t MODULEID;
  330. uint8_t RESERVED;
  331. uint16_t MLENGTH;
  332. uint32_t MOFFSET;
  333. }
  334. * confirm;
  335. #ifndef __GNUC__
  336. #pragma pack (pop)
  337. #endif
  338. uint16_t length = oINTELLON_BLOCKSIZE;
  339. uint16_t extent = this->mextent;
  340. uint32_t offset = 0;
  341. intellon.ImportPeerAddress (channel->PeerAddress ());
  342. intellon.ImportHostAddress (channel->HostAddress ());
  343. intellon.SetMessageType (VS_WR_MOD | MMTYPE_REQ);
  344. while (extent)
  345. {
  346. if (length > extent)
  347. {
  348. length = extent;
  349. }
  350. std::memset (message, 0, sizeof (message));
  351. request = (struct vs_wr_mod_request *) (intellon.ExportHeader (message));
  352. confirm = (struct vs_wr_mod_confirm *) (request);
  353. std::memcpy (request->MBUFFER, this->mbuffer + offset, length);
  354. request->MODULEID = VS_MODULE_MAC;
  355. request->RESERVED = 0;
  356. request->MLENGTH = HTOLE16 (length);
  357. request->MOFFSET = HTOLE32 (offset);
  358. request->MCHKSUM = omemory::checksum32 (request->MBUFFER, length, 0);
  359. if (channel->SendMessage (message, intellon.BufferLength (sizeof (struct vs_wr_mod_request))) <= 0)
  360. {
  361. oerror::error (0, ECANCELED, CPLCHANNEL_CANTSEND);
  362. return (-1);
  363. }
  364. if (channel->ReadMessage (message, sizeof (message)) <= 0)
  365. {
  366. oerror::error (0, ECANCELED, CPLCHANNEL_CANTREAD);
  367. return (-1);
  368. }
  369. if (confirm->MSTATUS)
  370. {
  371. oerror::error (0, ECANCELED, CPLCHANNEL_WONTDOIT);
  372. return (-1);
  373. }
  374. #if 1
  375. if (LE16TOH (confirm->MLENGTH) != length)
  376. {
  377. oerror::error (0, ECANCELED, oINTELLON_BAD_LENGTH);
  378. return (-1);
  379. }
  380. if (LE32TOH (confirm->MOFFSET) != offset)
  381. {
  382. oerror::error (0, ECANCELED, oINTELLON_BAD_OFFSET);
  383. return (-1);
  384. }
  385. #else
  386. if (LE16TOH (confirm->MLENGTH) != length)
  387. {
  388. oerror::error (0, EIO, oINTELLON_BAD_LENGTH);
  389. length = oINTELLON_BLOCKSIZE;
  390. offset = 0;
  391. continue;
  392. }
  393. if (LE32TOH (confirm->MOFFSET) != offset)
  394. {
  395. oerror::error (0, EIO, oINTELLON_BAD_OFFSET);
  396. length = oINTELLON_BLOCKSIZE;
  397. offset = 0;
  398. continue;
  399. }
  400. #endif
  401. offset += length;
  402. extent -= length;
  403. }
  404. return (0);
  405. }
  406. /*====================================================================*
  407. *
  408. * signed Flash (CPLChannel *channel);
  409. *
  410. * commit downloaded firmware image sequence to flash memory;
  411. *
  412. *--------------------------------------------------------------------*/
  413. signed CPLFirmware::Flash (CPLChannel *channel)
  414. {
  415. ointellon intellon;
  416. uint8_t message [ETHER_MAX_LEN];
  417. #ifndef __GNUC__
  418. #pragma pack (push,1)
  419. #endif
  420. struct __packed vs_wr_mod_nvm_request
  421. {
  422. uint8_t MODULEID;
  423. uint8_t RESERVED;
  424. }
  425. * request;
  426. struct __packed vs_wr_mod_nvm_confirm
  427. {
  428. uint8_t MSTATUS;
  429. uint8_t MODULEID;
  430. }
  431. * confirm;
  432. #ifndef __GNUC__
  433. #pragma pack (pop)
  434. #endif
  435. intellon.ImportPeerAddress (channel->PeerAddress ());
  436. intellon.ImportHostAddress (channel->HostAddress ());
  437. intellon.SetMessageType (VS_MOD_NVM | MMTYPE_REQ);
  438. request = (struct vs_wr_mod_nvm_request *) (intellon.ExportHeader (message));
  439. confirm = (struct vs_wr_mod_nvm_confirm *) (request);
  440. request->MODULEID = VS_MODULE_MAC;
  441. request->RESERVED = 0;
  442. if (channel->SendMessage (message, ETHER_MIN_LEN) <= 0)
  443. {
  444. oerror::error (0, ECANCELED, CPLCHANNEL_CANTSEND);
  445. return (-1);
  446. }
  447. if (channel->ReadMessage (message, sizeof (message)) <= 0)
  448. {
  449. oerror::error (0, ECANCELED, CPLCHANNEL_CANTREAD);
  450. return (-1);
  451. }
  452. if (confirm->MSTATUS)
  453. {
  454. oerror::error (0, ECANCELED, CPLCHANNEL_WONTDOIT);
  455. return (-1);
  456. }
  457. return (0);
  458. }
  459. /*====================================================================*
  460. *
  461. * CPLFirmware & CPLFirmware::Peek (void const * memory);
  462. *
  463. *--------------------------------------------------------------------*/
  464. void CPLFirmware::Peek (void const * memory) const
  465. {
  466. CPLFirmware::Header const * header = (CPLFirmware::Header const *)(memory);
  467. static char const * platforms [] =
  468. {
  469. "INT6000",
  470. "INT6300",
  471. "INT6400",
  472. "AR7400",
  473. (char const *)(0)
  474. };
  475. static char const * functions []=
  476. {
  477. "Generic Image",
  478. "Synopsis Configuration",
  479. "Denali Configuration",
  480. "Denali Applet",
  481. "Firmware Image",
  482. "OAS Client",
  483. "Custom Image",
  484. "Memory Control",
  485. };
  486. std::printf ("\tHeader Version = 0x%08X-%02X\n", LE32TOH (header->HEADERVERSION), header->HEADERMINORVERSION);
  487. std::printf ("\tHeader Checksum = 0x%08X\n", LE32TOH (header->HEADERCHECKSUM));
  488. std::printf ("\tHeader Next = 0x%08X\n", LE32TOH (header->NEXTHEADER));
  489. std::printf ("\tFlash Address = 0x%08X\n", LE32TOH (header->IMAGEROMADDR));
  490. std::printf ("\tImage Address = 0x%08X\n", LE32TOH (header->IMAGEADDR));
  491. std::printf ("\tEntry Address = 0x%08X\n", LE32TOH (header->ENTRYPOINT));
  492. std::printf ("\tImage Checksum = 0x%08X\n", LE32TOH (header->IMAGECHECKSUM));
  493. std::printf ("\tImage Size = 0x%08X (%d)\n", LE32TOH (header->IMAGELENGTH), LE32TOH (header->IMAGELENGTH));
  494. if (header->IMAGETYPE < (sizeof (functions) / sizeof (char const *)))
  495. {
  496. std::printf ("\tImage Type = %s\n", functions [header->IMAGETYPE]);
  497. }
  498. else
  499. {
  500. std::cout << "\tImage Type = Unknown" << std::endl;
  501. }
  502. std::cout << "\tImage Omit = ";
  503. CPLFirmware::bitmap (platforms, LE16TOH (header->IGNOREMASK));
  504. std::cout << std::endl;
  505. std::cout << std::endl;
  506. return;
  507. }
  508. /*====================================================================*
  509. *
  510. * void bitmap (char const *operands [], unsigned flagword) const;
  511. *
  512. *--------------------------------------------------------------------*/
  513. void CPLFirmware::bitmap (char const * operands [], unsigned flagword) const
  514. {
  515. char const * separator = "";
  516. while ((*operands) && (flagword))
  517. {
  518. if (flagword & 1)
  519. {
  520. std::cout << separator << *operands;
  521. separator = "|";
  522. }
  523. flagword >>= 1;
  524. operands++;
  525. }
  526. return;
  527. }
  528. /*====================================================================*
  529. *
  530. * CPLFirmware & CPLFirmware::Init ();
  531. *
  532. * initialize instance variable;
  533. *
  534. *--------------------------------------------------------------------*/
  535. CPLFirmware & CPLFirmware::Init ()
  536. {
  537. this->mbuffer = (uint8_t *)(0);
  538. this->mextent = 0;
  539. return (*this);
  540. }
  541. /*====================================================================*
  542. *
  543. * CPLFirmware (CPLChannel * channel)
  544. *
  545. *--------------------------------------------------------------------*/
  546. #if 0
  547. CPLFirmware::CPLFirmware (CPLChannel * channel)
  548. {
  549. this->Init ().Read (channel);
  550. return;
  551. }
  552. #endif
  553. /*====================================================================*
  554. *
  555. * CPLFirmware (char const * filename)
  556. *
  557. *--------------------------------------------------------------------*/
  558. CPLFirmware::CPLFirmware (char const * filename)
  559. {
  560. this->Init ().Read (filename);
  561. return;
  562. }
  563. /*====================================================================*
  564. *
  565. * ~CPLFirmware ()
  566. *
  567. *--------------------------------------------------------------------*/
  568. CPLFirmware::~CPLFirmware ()
  569. {
  570. std::cout << "delete mbuffer" << std::endl;
  571. delete [] this->mbuffer;
  572. std::cout << "delete mbuffer" << std::endl;
  573. return;
  574. }
  575. /*====================================================================*
  576. * end definition;
  577. *--------------------------------------------------------------------*/
  578. #endif