int recovery_init (void) { struct recovery_message msg; struct update_header header; char partition_name[32]; unsigned valid_command = 0; // get recovery message if(get_recovery_message(&msg)) return -1; if (msg.command[0] != 0 && msg.command[0] != 255) { dprintf("Recovery command: %.*s\n", sizeof(msg.command), msg.command); } msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination if (!strcmp("boot-recovery",msg.command)) { valid_command = 1; strcpy(msg.command, ""); // to safe against multiple reboot into recovery strcpy(msg.status, "OKAY"); set_recovery_message(&msg); // send recovery message boot_into_recovery = 1; // Boot in recovery mode return 0; } // cedesmith: wince phone update radio and boot loader using spl #ifndef WSPL_VADDR if (!strcmp("update-radio",msg.command)) { valid_command = 1; strcpy(partition_name, "FOTA"); } //Todo: Add support for bootloader update too. #endif if(!valid_command) { //We need not to do anything return 0; // Boot in normal mode } if (read_update_header_for_bootloader(&header)) { strcpy(msg.status, "invalid-update"); goto SEND_RECOVERY_MSG; } if (update_firmware_image (&header, partition_name)) { strcpy(msg.status, "failed-update"); goto SEND_RECOVERY_MSG; } strcpy(msg.status, "OKAY"); SEND_RECOVERY_MSG: strcpy(msg.command, "boot-recovery"); set_recovery_message(&msg); // send recovery message boot_into_recovery = 1; // Boot in recovery mode reboot_device(0); return 0; }
int recovery_init (void) { struct recovery_message msg; char partition_name[32]; unsigned valid_command = 0; int update_status = 0; // get recovery message if (get_recovery_message(&msg)) return -1; msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination if (msg.command[0] != 0 && msg.command[0] != 255) { dprintf(INFO,"Recovery command: %d %s\n", sizeof(msg.command), msg.command); } if (!strcmp("boot-recovery",msg.command)) { if(!strcmp("RADIO",msg.status)) { /* We're now here due to radio update, so check for update status */ int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status); if(!ret && (update_status & 0x01)) { dprintf(INFO,"radio update success\n"); strlcpy(msg.status, "OKAY", sizeof(msg.status)); } else { dprintf(INFO,"radio update failed\n"); strlcpy(msg.status, "failed-update", sizeof(msg.status)); } strlcpy(msg.command, "", sizeof(msg.command)); // clearing recovery command set_recovery_message(&msg); // send recovery message boot_into_recovery = 1; // Boot in recovery mode return 0; } valid_command = 1; strlcpy(msg.command, "", sizeof(msg.command)); // to safe against multiple reboot into recovery strlcpy(msg.status, "OKAY", sizeof(msg.status)); set_recovery_message(&msg); // send recovery message boot_into_recovery = 1; // Boot in recovery mode return 0; } if (!strcmp("update-radio",msg.command)) { dprintf(INFO,"start radio update\n"); valid_command = 1; strlcpy(partition_name, "FOTA", sizeof(partition_name)); } //Todo: Add support for bootloader update too. if(!valid_command) { //We need not to do anything return 0; // Boot in normal mode } #ifdef OLD_FOTA_UPGRADE if (read_update_header_for_bootloader(&header)) { strlcpy(msg.status, "invalid-update", sizeof(msg.status)); goto SEND_RECOVERY_MSG; } if (update_firmware_image (&header, partition_name)) { strlcpy(msg.status, "failed-update", sizeof(msg.status)); goto SEND_RECOVERY_MSG; } #else if (set_ssd_radio_update(partition_name)) { /* If writing to FOTA partition fails */ strlcpy(msg.command, "", sizeof(msg.command)); strlcpy(msg.status, "failed-update", sizeof(msg.status)); goto SEND_RECOVERY_MSG; } else { /* Setting this to check the radio update status */ strlcpy(msg.command, "boot-recovery", sizeof(msg.command)); strlcpy(msg.status, "RADIO", sizeof(msg.status)); goto SEND_RECOVERY_MSG; } #endif strlcpy(msg.status, "OKAY", sizeof(msg.status)); SEND_RECOVERY_MSG: set_recovery_message(&msg); // send recovery message boot_into_recovery = 1; // Boot in recovery mode reboot_device(0); return 0; }
int update_firmware_image (struct update_header *header, char *name) { struct ptentry *ptn; struct ptable *ptable; unsigned offset = 0; unsigned pagesize = flash_page_size(); unsigned pagemask = pagesize -1; unsigned n = 0; ptable = flash_get_ptable(); if (ptable == NULL) { dprintf(CRITICAL, "ERROR: Partition table not found\n"); return -1; } ptn = ptable_find(ptable, "cache"); if (ptn == NULL) { dprintf(CRITICAL, "ERROR: No cache partition found\n"); return -1; } offset += header->image_offset; n = (header->image_length + pagemask) & (~pagemask); if (flash_read(ptn, offset, SCRATCH_ADDR, n)) { dprintf(CRITICAL, "ERROR: Cannot read radio image\n"); return -1; } if (!strcmp(name, "radio")) { ptn = ptable_find(ptable, name); if (ptn == NULL) { dprintf(CRITICAL, "ERROR: No %s partition found\n", name); return -1; } if (flash_write(ptn, 0, SCRATCH_ADDR, n)) { dprintf(CRITICAL, "ERROR: flash write fail!\n"); return -1; } } else if (!strcmp(name, "bootloader")) { #ifdef PLATFORM_TCC struct ptentry ptn = { .name = "bootloader", }; flash_write(&ptn, 0, SCRATCH_ADDR, n); #endif } dprintf(INFO, "Partition writen successfully!"); return 0; } /* Bootloader / Recovery Flow * * On every boot, the bootloader will read the recovery_message * from flash and check the command field. The bootloader should * deal with the command field not having a 0 terminator correctly * (so as to not crash if the block is invalid or corrupt). * * The bootloader will have to publish the partition that contains * the recovery_message to the linux kernel so it can update it. * * if command == "boot-recovery" -> boot recovery.img * else if command == "update-radio" -> update radio image (below) * else -> boot boot.img (normal boot) * * Radio Update Flow * 1. the bootloader will attempt to load and validate the header * 2. if the header is invalid, status="invalid-update", goto #8 * 3. display the busy image on-screen * 4. if the update image is invalid, status="invalid-radio-image", goto #8 * 5. attempt to update the firmware (depending on the command) * 6. if successful, status="okay", goto #8 * 7. if failed, and the old image can still boot, status="failed-update" * 8. write the recovery_message, leaving the recovery field * unchanged, updating status, and setting command to * "boot-recovery" * 9. reboot * * The bootloader will not modify or erase the cache partition. * It is recovery's responsibility to clean up the mess afterwards. */ int recovery_init (void) { struct recovery_message msg; struct update_header header; char partition_name[32]; unsigned valid_command = 0; // get recovery message if(get_recovery_message(&msg)) return -1; if (msg.command[0] != 0 && msg.command[0] != 255) { dprintf(INFO, "Recovery command: %s\n", msg.command); } msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination if (!strcmp("boot-recovery",msg.command)) { valid_command = 1; strcpy(msg.command, ""); // to safe against multiple reboot into recovery strcpy(msg.status, "OKAY"); set_recovery_message(&msg); // send recovery message boot_into_recovery = 1; // Boot in recovery mode return 0; } if (!strcmp("update-radio",msg.command)) { valid_command = 1; strcpy(partition_name, "AMSS"); } else if (!strcmp("update-bootloader", msg.command)) { valid_command = 1; strcpy(partition_name, "bootloader"); } if(!valid_command) { //We need not to do anything return 0; // Boot in normal mode } if (read_update_header_for_bootloader(&header)) { strcpy(msg.status, "invalid-update"); goto SEND_RECOVERY_MSG; } if (update_firmware_image (&header, partition_name)) { strcpy(msg.status, "failed-update"); goto SEND_RECOVERY_MSG; } strcpy(msg.status, "OKAY"); SEND_RECOVERY_MSG: strcpy(msg.command, "boot-recovery"); set_recovery_message(&msg); // send recovery message boot_into_recovery = 1; // Boot in recovery mode reboot_device(0); return 0; } #elif defined(TNFTL_V8_INCLUDE) static int set_recovery_msg_v8(struct recovery_message *out) { char *ptn_name = "misc"; unsigned long long ptn = 0; unsigned int size = ROUND_TO_PAGE(sizeof(*out),511); unsigned char data[size]; ptn = flash_ptn_offset(ptn_name); if(ptn == 0) { dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name); return -1; } memcpy(data, out, sizeof(*out)); if (flash_write_tnftl_v8(ptn_name, ptn , size, (unsigned int*)data)) { dprintf(CRITICAL,"write failure %s %d\n",ptn_name, sizeof(*out)); return -1; } return 0; }