int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid, disk_partition_t *partitions, int parts_count) { int ret; gpt_header *gpt_h = calloc(1, PAD_TO_BLOCKSIZE(sizeof(gpt_header), dev_desc)); gpt_entry *gpt_e; if (gpt_h == NULL) { printf("%s: calloc failed!\n", __func__); return -1; } gpt_e = calloc(1, PAD_TO_BLOCKSIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), dev_desc)); if (gpt_e == NULL) { printf("%s: calloc failed!\n", __func__); free(gpt_h); return -1; } /* Generate Primary GPT header (LBA1) */ ret = gpt_fill_header(dev_desc, gpt_h, str_disk_guid, parts_count); if (ret) goto err; /* Generate partition entries */ ret = gpt_fill_pte(gpt_h, gpt_e, partitions, parts_count); if (ret) goto err; /* Write GPT partition table */ ret = write_gpt_table(dev_desc, gpt_h, gpt_e); err: free(gpt_e); free(gpt_h); return ret; }
/** * alloc_read_gpt_entries(): reads partition entries from disk * @dev_desc * @gpt - GPT header * * Description: Returns ptes on success, NULL on error. * Allocates space for PTEs based on information found in @gpt. * Notes: remember to free pte when you're done! */ static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc, gpt_header * pgpt_head) { size_t count = 0, blk_cnt; gpt_entry *pte = NULL; if (!dev_desc || !pgpt_head) { printf("%s: Invalid Argument(s)\n", __func__); return NULL; } count = le32_to_cpu(pgpt_head->num_partition_entries) * le32_to_cpu(pgpt_head->sizeof_partition_entry); debug("%s: count = %u * %u = %zu\n", __func__, (u32) le32_to_cpu(pgpt_head->num_partition_entries), (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry), count); /* Allocate memory for PTE, remember to FREE */ if (count != 0) { pte = memalign(ARCH_DMA_MINALIGN, PAD_TO_BLOCKSIZE(count, dev_desc)); } if (count == 0 || pte == NULL) { printf("%s: ERROR: Can't allocate 0x%zX " "bytes for GPT Entries\n", __func__, count); return NULL; } /* Read GPT Entries from device */ blk_cnt = BLOCK_CNT(count, dev_desc); if (dev_desc->block_read (dev_desc->dev, le64_to_cpu(pgpt_head->partition_entry_lba), (lbaint_t) (blk_cnt), pte) != blk_cnt) { printf("*** ERROR: Can't read GPT Entries ***\n"); free(pte); return NULL; } return pte; }
void fb_mmc_flash_write(const char *cmd, void *download_buffer, unsigned int download_bytes, char *response) { int ret; int expected; int pte_blk_cnt; block_dev_desc_t *dev_desc; disk_partition_t info; /* initialize the response buffer */ response_str = response; legacy_mbr *mbr; gpt_header *primary_gpt_h; gpt_entry *second_gpt_e; dev_desc = get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { error("invalid mmc device\n"); fastboot_fail("invalid mmc device"); return; } #if 0 char cmd_buf[64] = {0}; ulong mmc_part; ulong mmc_flash_start; if (!strncmp("to:", cmd, strlen("to:"))) { strsep(&cmd, ":"); if (!cmd) { error("missing variable\n"); fastboot_fail("missing var"); return; } mmc_part = simple_strtoul(cmd, NULL, 10); if(mmc_part > 16){ error("Part # is too large\n"); fastboot_fail("Part # is too large"); return; } strsep(&cmd, ":"); if (!cmd) { error("missing variable\n"); fastboot_fail("missing var"); return; } mmc_flash_start = simple_strtoul(cmd, NULL, 16); if(mmc_flash_start != PAD_TO_BLOCKSIZE(mmc_flash_start, dev_desc)){ error("Offset must start from block size boudry\n"); fastboot_fail("Offset must start from block size boudry"); return; } sprintf(cmd_buf, "mmc dev %d %d", CONFIG_FASTBOOT_FLASH_MMC_DEV, mmc_part); run_command(cmd_buf, 0); if(dev_desc->lba != 0){ if (dev_desc->block_write(dev_desc->dev, mmc_flash_start/dev_desc->blksz, BLOCK_CNT(download_bytes, dev_desc), download_buffer) != BLOCK_CNT(download_bytes, dev_desc)){ error("flash data failed:\n"); fastboot_fail("flash data failed:"); }else{ fastboot_okay(""); } }else{ error("Invalid mmc part\n"); fastboot_fail("Invalid mmc part"); } /* switch back to main part */ sprintf(cmd_buf, "mmc dev %d 0", CONFIG_FASTBOOT_FLASH_MMC_DEV); run_command(cmd_buf, 0); }else #endif if (!strncmp("partition", cmd, strlen("partition"))) { /*do sanity check of the downloader data */ expected = sizeof(legacy_mbr) + 2 * ((PAD_TO_BLOCKSIZE(sizeof(gpt_header), dev_desc) + PAD_TO_BLOCKSIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), dev_desc))); if(expected != download_bytes){ error("wrong size for download data, expected: %d\n", expected); fastboot_fail("wrong size for download data"); return; } mbr = download_buffer; primary_gpt_h = (void *)mbr + sizeof(legacy_mbr); pte_blk_cnt = BLOCK_CNT((primary_gpt_h->num_partition_entries * sizeof(gpt_entry)), dev_desc); second_gpt_e = primary_gpt_h + PAD_TO_BLOCKSIZE(sizeof(gpt_header), dev_desc) + PAD_TO_BLOCKSIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), dev_desc); /* Check the MBR signature */ if (le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE){ error("MBR signature is wrong:" "0x%X != 0x%X\n", le16_to_cpu(mbr->signature), MSDOS_MBR_SIGNATURE); fastboot_fail("wrong data"); return; } /* Check the GPT header signature */ if (le64_to_cpu(primary_gpt_h->signature) != GPT_HEADER_SIGNATURE) { error("GUID Partition Table Header signature is wrong:" "0x%llX != 0x%llX\n", le64_to_cpu(primary_gpt_h->signature), GPT_HEADER_SIGNATURE); fastboot_fail("wrong data"); return; } /* Write the Legacy MBR */ if (dev_desc->block_write(dev_desc->dev, 0, 1, mbr) != 1){ printf("Write mbr failed!\n"); goto err; } /* Write the First GPT to the block right after the Legacy MBR */ if (dev_desc->block_write(dev_desc->dev, 1, pte_blk_cnt + 1, primary_gpt_h) != pte_blk_cnt + 1){ printf("Write primary gpt failed!\n"); goto err; } /*Write the Second GPT at the end of the block*/ lbaint_t second_gpt_offset = le32_to_cpu(primary_gpt_h->last_usable_lba + 1); if(dev_desc->block_write(dev_desc->dev, second_gpt_offset, pte_blk_cnt + 1, second_gpt_e) != pte_blk_cnt + 1){ printf("write second gpt failed!\n"); goto err; } #if 0 /* do sanity check of the download data */ expected = sizeof(legacy_mbr)+ 1 * (PAD_TO_BLOCKSIZE(sizeof(gpt_header), dev_desc)+PAD_TO_BLOCKSIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), dev_desc)); /*if(expected != download_bytes){ error("wrong size for download data, expected: %d\n", expected); fastboot_fail("wrong size for download data"); return; }*/ printf("legacy_mbr is %d, gpt_header is %d, gpt_entry is %d\n",sizeof(legacy_mbr),PAD_TO_BLOCKSIZE(sizeof(gpt_header), dev_desc),PAD_TO_BLOCKSIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), dev_desc)); mbr = download_buffer; gpt_h = (void *)mbr + sizeof(legacy_mbr); gpt_e = (void *)gpt_h+PAD_TO_BLOCKSIZE(sizeof(gpt_header), dev_desc); /* Check the MBR signature */ if (le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE){ error("MBR signature is wrong:" "0x%X != 0x%X\n", le16_to_cpu(mbr->signature), MSDOS_MBR_SIGNATURE); fastboot_fail("wrong data"); return; } /* Check the GPT header signature */ if (le64_to_cpu(gpt_h->signature) != GPT_HEADER_SIGNATURE) { error("GUID Partition Table Header signature is wrong:" "0x%llX != 0x%llX\n", le64_to_cpu(gpt_h->signature), GPT_HEADER_SIGNATURE); fastboot_fail("wrong data"); return; } const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries * sizeof(gpt_entry)), dev_desc); u32 calc_crc32; u64 val; printf("max lba: %x\n", (u32) dev_desc->lba); printf("last_usable_lba is %d, my_lba is %d, pte_blk_cnt is %d\n",le32_to_cpu(gpt_h->last_usable_lba + 1),le32_to_cpu(gpt_h->my_lba), pte_blk_cnt); /* Write the Legacy MBR */ if (dev_desc->block_write(dev_desc->dev, 0, 1, mbr) != 1){ printf("Write mbr failed!\n"); goto err; } printf("last_usable_lba is %d, my_lba is %d, pte_blk_cnt is %d\n",le32_to_cpu(gpt_h->last_usable_lba + 1),le32_to_cpu(gpt_h->my_lba), pte_blk_cnt); /* Write the First GPT to the block right after the Legacy MBR */ if (dev_desc->block_write(dev_desc->dev, 1, 1, gpt_h) != 1){ printf("Write gpt header failed!\n"); goto err; } printf("last_usable_lba is %d, my_lba is %d, pte_blk_cnt is %d\n",le32_to_cpu(gpt_h->last_usable_lba + 1),le32_to_cpu(gpt_h->my_lba), pte_blk_cnt); if (dev_desc->block_write(dev_desc->dev, 2, pte_blk_cnt, gpt_e) != pte_blk_cnt){ printf("Write gpt_e failed!\n"); goto err; } printf("last_usable_lba is %d, my_lba is %d, pte_blk_cnt is %d\n",le32_to_cpu(gpt_h->last_usable_lba + 1),le32_to_cpu(gpt_h->my_lba), pte_blk_cnt); /* recalculate the values for the Second GPT Header */ printf("last_usable_lba is %d, my_lba is %d, pte_blk_cnt is %d\n",le32_to_cpu(gpt_h->last_usable_lba + 1),le32_to_cpu(gpt_h->my_lba), pte_blk_cnt); val = le64_to_cpu(gpt_h->my_lba); gpt_h->my_lba = gpt_h->alternate_lba; gpt_h->alternate_lba = cpu_to_le64(val); gpt_h->header_crc32 = 0; calc_crc32 = crc32(0, (const unsigned char *)gpt_h, le32_to_cpu(gpt_h->header_size)); gpt_h->header_crc32 = cpu_to_le32(calc_crc32); printf("last_usable_lba is %d, my_lba is %d, pte_blk_cnt is %d\n",le32_to_cpu(gpt_h->last_usable_lba + 1),le32_to_cpu(gpt_h->my_lba), pte_blk_cnt); if (dev_desc->block_write(dev_desc->dev, le32_to_cpu(gpt_h->last_usable_lba + 1), pte_blk_cnt, gpt_e) != pte_blk_cnt){ printf("Write second gpt_e failed!\n"); goto err; } if (dev_desc->block_write(dev_desc->dev, le32_to_cpu(gpt_h->my_lba), 1, gpt_h) != 1){ printf("Write second gpt_h failed!\n"); goto err; } #endif printf("GPT successfully written to block device!\n"); fastboot_okay(""); return; err: error("flash partition data failed: '%s'\n", cmd); fastboot_fail("cannot flash partition"); return; }else{ ret = get_partition_info_efi_by_name(dev_desc, cmd, &info); if (ret) { error("cannot find partition: '%s'\n", cmd); fastboot_fail("cannot find partition"); return; } if (is_sparse_image(download_buffer)) write_sparse_image(dev_desc, &info, cmd, download_buffer, download_bytes); else write_raw_image(dev_desc, &info, cmd, download_buffer, download_bytes); } }