recovery.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
  2. * Redistribution and use in source and binary forms, with or without
  3. * modification, are permitted provided that the following conditions are
  4. * met:
  5. * * Redistributions of source code must retain the above copyright
  6. * notice, this list of conditions and the following disclaimer.
  7. * * Redistributions in binary form must reproduce the above
  8. * copyright notice, this list of conditions and the following
  9. * disclaimer in the documentation and/or other materials provided
  10. * with the distribution.
  11. * * Neither the name of Code Aurora Forum, Inc. nor the names of its
  12. * contributors may be used to endorse or promote products derived
  13. * from this software without specific prior written permission.
  14. *
  15. * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
  16. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
  18. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
  19. * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  20. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  21. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  22. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  23. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  24. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  25. * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <debug.h>
  28. #include <arch/arm.h>
  29. #include <dev/udc.h>
  30. #include <string.h>
  31. #include <kernel/thread.h>
  32. #include <arch/ops.h>
  33. #include <dev/flash.h>
  34. #include <lib/ptable.h>
  35. #include <dev/keys.h>
  36. #include <platform.h>
  37. #include <partition_parser.h>
  38. #include <mmc.h>
  39. #include "recovery.h"
  40. #include "bootimg.h"
  41. //#include "smem.h"
  42. #define BOOT_FLAGS 1
  43. #define UPDATE_STATUS 2
  44. #define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
  45. static const int MISC_PAGES = 3; // number of pages to save
  46. static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
  47. static char buf[4096];
  48. unsigned boot_into_recovery = 0;
  49. extern void reset_device_info();
  50. extern void set_device_root();
  51. int get_recovery_message(struct recovery_message *out)
  52. {
  53. struct ptentry *ptn;
  54. struct ptable *ptable;
  55. unsigned offset = 0;
  56. unsigned pagesize = flash_page_size();
  57. ptable = flash_get_ptable();
  58. if (ptable == NULL) {
  59. dprintf(CRITICAL, "ERROR: Partition table not found\n");
  60. return -1;
  61. }
  62. ptn = ptable_find(ptable, "misc");
  63. if (ptn == NULL) {
  64. dprintf(CRITICAL, "ERROR: No misc partition found\n");
  65. return -1;
  66. }
  67. offset += (pagesize * MISC_COMMAND_PAGE);
  68. if (flash_read(ptn, offset, (void *) buf, pagesize)) {
  69. dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
  70. return -1;
  71. }
  72. memcpy(out, buf, sizeof(*out));
  73. return 0;
  74. }
  75. int set_recovery_message(const struct recovery_message *in)
  76. {
  77. struct ptentry *ptn;
  78. struct ptable *ptable;
  79. unsigned offset = 0;
  80. unsigned pagesize = flash_page_size();
  81. unsigned n = 0;
  82. ptable = flash_get_ptable();
  83. if (ptable == NULL) {
  84. dprintf(CRITICAL, "ERROR: Partition table not found\n");
  85. return -1;
  86. }
  87. ptn = ptable_find(ptable, "misc");
  88. if (ptn == NULL) {
  89. dprintf(CRITICAL, "ERROR: No misc partition found\n");
  90. return -1;
  91. }
  92. n = pagesize * (MISC_COMMAND_PAGE + 1);
  93. if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
  94. dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
  95. return -1;
  96. }
  97. offset += (pagesize * MISC_COMMAND_PAGE);
  98. offset += SCRATCH_ADDR;
  99. memcpy((void *) offset, in, sizeof(*in));
  100. if (flash_write(ptn, 0, (void *)SCRATCH_ADDR, n)) {
  101. dprintf(CRITICAL, "ERROR: flash write fail!\n");
  102. return -1;
  103. }
  104. return 0;
  105. }
  106. int read_update_header_for_bootloader(struct update_header *header)
  107. {
  108. struct ptentry *ptn;
  109. struct ptable *ptable;
  110. unsigned offset = 0;
  111. unsigned pagesize = flash_page_size();
  112. ptable = flash_get_ptable();
  113. if (ptable == NULL) {
  114. dprintf(CRITICAL, "ERROR: Partition table not found\n");
  115. return -1;
  116. }
  117. ptn = ptable_find(ptable, "cache");
  118. if (ptn == NULL) {
  119. dprintf(CRITICAL, "ERROR: No cache partition found\n");
  120. return -1;
  121. }
  122. if (flash_read(ptn, offset, buf, pagesize)) {
  123. dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
  124. return -1;
  125. }
  126. memcpy(header, buf, sizeof(*header));
  127. if (strncmp((char *) header->MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE))
  128. {
  129. return -1;
  130. }
  131. return 0;
  132. }
  133. int update_firmware_image (struct update_header *header, char *name)
  134. {
  135. struct ptentry *ptn;
  136. struct ptable *ptable;
  137. unsigned offset = 0;
  138. unsigned pagesize = flash_page_size();
  139. unsigned pagemask = pagesize -1;
  140. unsigned n = 0;
  141. ptable = flash_get_ptable();
  142. if (ptable == NULL) {
  143. dprintf(CRITICAL, "ERROR: Partition table not found\n");
  144. return -1;
  145. }
  146. ptn = ptable_find(ptable, "cache");
  147. if (ptn == NULL) {
  148. dprintf(CRITICAL, "ERROR: No cache partition found\n");
  149. return -1;
  150. }
  151. offset += header->image_offset;
  152. n = (header->image_length + pagemask) & (~pagemask);
  153. if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
  154. dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
  155. return -1;
  156. }
  157. ptn = ptable_find(ptable, name);
  158. if (ptn == NULL) {
  159. dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
  160. return -1;
  161. }
  162. if (flash_write(ptn, 0, (void *) SCRATCH_ADDR, n)) {
  163. dprintf(CRITICAL, "ERROR: flash write fail!\n");
  164. return -1;
  165. }
  166. dprintf(INFO, "Partition writen successfully!");
  167. return 0;
  168. }
  169. static int set_ssd_radio_update (char *name)
  170. {
  171. struct ptentry *ptn;
  172. struct ptable *ptable;
  173. unsigned int ssd_cookie[2] = {0x53534443, 0x4F4F4B49};
  174. unsigned pagesize = flash_page_size();
  175. unsigned pagemask = pagesize -1;
  176. unsigned n = 0;
  177. ptable = flash_get_ptable();
  178. if (ptable == NULL) {
  179. dprintf(CRITICAL, "ERROR: Partition table not found\n");
  180. return -1;
  181. }
  182. n = (sizeof(ssd_cookie) + pagemask) & (~pagemask);
  183. ptn = ptable_find(ptable, name);
  184. if (ptn == NULL) {
  185. dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
  186. return -1;
  187. }
  188. if (flash_write(ptn, 0, ssd_cookie, n)) {
  189. dprintf(CRITICAL, "ERROR: flash write fail!\n");
  190. return -1;
  191. }
  192. dprintf(INFO, "FOTA partition written successfully!");
  193. return 0;
  194. }
  195. int get_boot_info_apps (char type, unsigned int *status)
  196. {
  197. /* Koshi's Note: Seems dedicated for Q* solutions */
  198. #if 0
  199. boot_info_for_apps apps_boot_info;
  200. int ret = 0;
  201. ret = smem_read_alloc_entry(SMEM_BOOT_INFO_FOR_APPS,
  202. &apps_boot_info, sizeof(apps_boot_info));
  203. if (ret)
  204. {
  205. dprintf(CRITICAL, "ERROR: unable to read shared memory for apps boot info %d\n",ret);
  206. return ret;
  207. }
  208. dprintf(INFO,"boot flag %x update status %x\n",apps_boot_info.boot_flags,
  209. apps_boot_info.status.update_status);
  210. if(type == BOOT_FLAGS)
  211. *status = apps_boot_info.boot_flags;
  212. else if(type == UPDATE_STATUS)
  213. *status = apps_boot_info.status.update_status;
  214. return ret;
  215. #endif
  216. return 0;
  217. }
  218. /* Bootloader / Recovery Flow
  219. *
  220. * On every boot, the bootloader will read the recovery_message
  221. * from flash and check the command field. The bootloader should
  222. * deal with the command field not having a 0 terminator correctly
  223. * (so as to not crash if the block is invalid or corrupt).
  224. *
  225. * The bootloader will have to publish the partition that contains
  226. * the recovery_message to the linux kernel so it can update it.
  227. *
  228. * if command == "boot-recovery" -> boot recovery.img
  229. * else if command == "update-radio" -> update radio image (below)
  230. * else -> boot boot.img (normal boot)
  231. *
  232. * Radio Update Flow
  233. * 1. the bootloader will attempt to load and validate the header
  234. * 2. if the header is invalid, status="invalid-update", goto #8
  235. * 3. display the busy image on-screen
  236. * 4. if the update image is invalid, status="invalid-radio-image", goto #8
  237. * 5. attempt to update the firmware (depending on the command)
  238. * 6. if successful, status="okay", goto #8
  239. * 7. if failed, and the old image can still boot, status="failed-update"
  240. * 8. write the recovery_message, leaving the recovery field
  241. * unchanged, updating status, and setting command to
  242. * "boot-recovery"
  243. * 9. reboot
  244. *
  245. * The bootloader will not modify or erase the cache partition.
  246. * It is recovery's responsibility to clean up the mess afterwards.
  247. */
  248. int recovery_init (void)
  249. {
  250. struct recovery_message msg;
  251. char partition_name[32];
  252. unsigned valid_command = 0;
  253. int update_status = 0;
  254. // get recovery message
  255. if (get_recovery_message(&msg))
  256. return -1;
  257. if (msg.command[0] != 0 && msg.command[0] != 255) {
  258. dprintf(INFO, "Recovery command: %.*s\n", sizeof(msg.command), msg.command);
  259. }
  260. msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
  261. if (!strcmp("boot-recovery",msg.command))
  262. {
  263. if(!strcmp("RADIO",msg.status))
  264. {
  265. /* We're now here due to radio update, so check for update status */
  266. int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
  267. if(!ret && (update_status & 0x01))
  268. {
  269. dprintf(INFO,"radio update success\n");
  270. strlcpy(msg.status, "OKAY", sizeof(msg.status));
  271. }
  272. else
  273. {
  274. dprintf(INFO,"radio update failed\n");
  275. strlcpy(msg.status, "failed-update", sizeof(msg.status));
  276. }
  277. strlcpy(msg.command, "", sizeof(msg.command)); // clearing recovery command
  278. set_recovery_message(&msg); // send recovery message
  279. boot_into_recovery = 1; // Boot in recovery mode
  280. return 0;
  281. }
  282. valid_command = 1;
  283. strlcpy(msg.command, "", sizeof(msg.command)); // to safe against multiple reboot into recovery
  284. strlcpy(msg.status, "OKAY", sizeof(msg.status));
  285. set_recovery_message(&msg); // send recovery message
  286. boot_into_recovery = 1; // Boot in recovery mode
  287. return 0;
  288. }
  289. if (!strcmp("update-radio",msg.command)) {
  290. dprintf(INFO,"start radio update\n");
  291. valid_command = 1;
  292. strlcpy(partition_name, "FOTA", sizeof(partition_name));
  293. }
  294. //Todo: Add support for bootloader update too.
  295. if(!valid_command) {
  296. //We need not to do anything
  297. return 0; // Boot in normal mode
  298. }
  299. #ifdef OLD_FOTA_UPGRADE
  300. if (read_update_header_for_bootloader(&header)) {
  301. strlcpy(msg.status, "invalid-update", sizeof(msg.status));
  302. goto SEND_RECOVERY_MSG;
  303. }
  304. if (update_firmware_image (&header, partition_name)) {
  305. strlcpy(msg.status, "failed-update", sizeof(msg.status));
  306. goto SEND_RECOVERY_MSG;
  307. }
  308. #else
  309. if (set_ssd_radio_update(partition_name)) {
  310. /* If writing to FOTA partition fails */
  311. strlcpy(msg.command, "", sizeof(msg.command));
  312. strlcpy(msg.status, "failed-update", sizeof(msg.status));
  313. goto SEND_RECOVERY_MSG;
  314. }
  315. else {
  316. /* Setting this to check the radio update status */
  317. strlcpy(msg.command, "boot-recovery", sizeof(msg.command));
  318. strlcpy(msg.status, "RADIO", sizeof(msg.status));
  319. goto SEND_RECOVERY_MSG;
  320. }
  321. #endif
  322. strlcpy(msg.status, "OKAY", sizeof(msg.status));
  323. SEND_RECOVERY_MSG:
  324. set_recovery_message(&msg); // send recovery message
  325. boot_into_recovery = 1; // Boot in recovery mode
  326. reboot_device(0);
  327. return 0;
  328. }
  329. static int emmc_set_recovery_msg(struct recovery_message *out)
  330. {
  331. char *ptn_name = "misc";
  332. unsigned long long ptn = 0;
  333. unsigned int size = ROUND_TO_PAGE(sizeof(*out),511);
  334. unsigned char data[size];
  335. int index = INVALID_PTN;
  336. index = partition_get_index((unsigned char *) ptn_name);
  337. ptn = partition_get_offset(index);
  338. if(ptn == 0) {
  339. dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
  340. return -1;
  341. }
  342. memcpy(data, out, sizeof(*out));
  343. if (mmc_write(ptn , size, (unsigned int*)data)) {
  344. dprintf(CRITICAL,"mmc write failure %s %d\n",ptn_name, sizeof(*out));
  345. return -1;
  346. }
  347. return 0;
  348. }
  349. static int emmc_get_recovery_msg(struct recovery_message *in)
  350. {
  351. char *ptn_name = "misc";
  352. unsigned long long ptn = 0;
  353. unsigned int size = ROUND_TO_PAGE(sizeof(*in),511);
  354. unsigned char data[size];
  355. int index = INVALID_PTN;
  356. index = partition_get_index((unsigned char *) ptn_name);
  357. ptn = partition_get_offset(index);
  358. if(ptn == 0) {
  359. dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
  360. return -1;
  361. }
  362. if (mmc_read(ptn , (unsigned int*)data, size)) {
  363. dprintf(CRITICAL,"mmc read failure %s %d\n",ptn_name, size);
  364. return -1;
  365. }
  366. memcpy(in, data, sizeof(*in));
  367. return 0;
  368. }
  369. int _emmc_recovery_init(void)
  370. {
  371. int update_status = 0;
  372. struct recovery_message msg;
  373. // get recovery message
  374. if(emmc_get_recovery_msg(&msg))
  375. return -1;
  376. if (msg.command[0] != 0 && msg.command[0] != 255) {
  377. dprintf(INFO,"Recovery command: %d %s\n", sizeof(msg.command), msg.command);
  378. }
  379. msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
  380. if (!strcmp("update-radio",msg.command))
  381. {
  382. /* We're now here due to radio update, so check for update status */
  383. int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
  384. if(!ret && (update_status & 0x01))
  385. {
  386. dprintf(INFO,"radio update success\n");
  387. strlcpy(msg.status, "OKAY", sizeof(msg.status));
  388. }
  389. else
  390. {
  391. dprintf(INFO,"radio update failed\n");
  392. strlcpy(msg.status, "failed-update", sizeof(msg.status));
  393. }
  394. boot_into_recovery = 1; // Boot in recovery mode
  395. }
  396. if (!strcmp("reset-device-info",msg.command))
  397. {
  398. reset_device_info();
  399. }
  400. if (!strcmp("root-detect",msg.command))
  401. {
  402. set_device_root();
  403. }
  404. else
  405. return 0; // do nothing
  406. strlcpy(msg.command, "", sizeof(msg.command)); // clearing recovery command
  407. emmc_set_recovery_msg(&msg); // send recovery message
  408. return 0;
  409. }