1 /* 2 * Copyright 2014 Broadcom Corporation. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <config.h> 8 #include <common.h> 9 #include <fb_mmc.h> 10 #include <part.h> 11 #include <aboot.h> 12 #include <sparse_format.h> 13 #include <mmc.h> 14 15 #ifndef CONFIG_FASTBOOT_GPT_NAME 16 #define CONFIG_FASTBOOT_GPT_NAME GPT_ENTRY_NAME 17 #endif 18 19 /* The 64 defined bytes plus the '\0' */ 20 #define RESPONSE_LEN (64 + 1) 21 22 static char *response_str; 23 24 void fastboot_fail(const char *s) 25 { 26 strncpy(response_str, "FAIL\0", 5); 27 strncat(response_str, s, RESPONSE_LEN - 4 - 1); 28 } 29 30 void fastboot_okay(const char *s) 31 { 32 strncpy(response_str, "OKAY\0", 5); 33 strncat(response_str, s, RESPONSE_LEN - 4 - 1); 34 } 35 36 static void write_raw_image(block_dev_desc_t *dev_desc, disk_partition_t *info, 37 const char *part_name, void *buffer, 38 unsigned int download_bytes) 39 { 40 lbaint_t blkcnt; 41 lbaint_t blks; 42 43 /* determine number of blocks to write */ 44 blkcnt = ((download_bytes + (info->blksz - 1)) & ~(info->blksz - 1)); 45 blkcnt = blkcnt / info->blksz; 46 47 if (blkcnt > info->size) { 48 error("too large for partition: '%s'\n", part_name); 49 fastboot_fail("too large for partition"); 50 return; 51 } 52 53 puts("Flashing Raw Image\n"); 54 55 blks = dev_desc->block_write(dev_desc->dev, info->start, blkcnt, 56 buffer); 57 if (blks != blkcnt) { 58 error("failed writing to device %d\n", dev_desc->dev); 59 fastboot_fail("failed writing to device"); 60 return; 61 } 62 63 printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz, 64 part_name); 65 fastboot_okay(""); 66 } 67 68 void fb_mmc_flash_write(const char *cmd, void *download_buffer, 69 unsigned int download_bytes, char *response) 70 { 71 block_dev_desc_t *dev_desc; 72 disk_partition_t info; 73 74 /* initialize the response buffer */ 75 response_str = response; 76 77 dev_desc = get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); 78 if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { 79 error("invalid mmc device\n"); 80 fastboot_fail("invalid mmc device"); 81 return; 82 } 83 84 if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0) { 85 printf("%s: updating MBR, Primary and Backup GPT(s)\n", 86 __func__); 87 if (is_valid_gpt_buf(dev_desc, download_buffer)) { 88 printf("%s: invalid GPT - refusing to write to flash\n", 89 __func__); 90 fastboot_fail("invalid GPT partition"); 91 return; 92 } 93 if (write_mbr_and_gpt_partitions(dev_desc, download_buffer)) { 94 printf("%s: writing GPT partitions failed\n", __func__); 95 fastboot_fail("writing GPT partitions failed"); 96 return; 97 } 98 printf("........ success\n"); 99 fastboot_okay(""); 100 return; 101 } else if (get_partition_info_efi_by_name(dev_desc, cmd, &info)) { 102 error("cannot find partition: '%s'\n", cmd); 103 fastboot_fail("cannot find partition"); 104 return; 105 } 106 107 if (is_sparse_image(download_buffer)) 108 write_sparse_image(dev_desc, &info, cmd, download_buffer, 109 download_bytes); 110 else 111 write_raw_image(dev_desc, &info, cmd, download_buffer, 112 download_bytes); 113 } 114 115 void fb_mmc_erase(const char *cmd, char *response) 116 { 117 int ret; 118 block_dev_desc_t *dev_desc; 119 disk_partition_t info; 120 lbaint_t blks, blks_start, blks_size, grp_size; 121 struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); 122 123 if (mmc == NULL) { 124 error("invalid mmc device"); 125 fastboot_fail("invalid mmc device"); 126 return; 127 } 128 129 /* initialize the response buffer */ 130 response_str = response; 131 132 dev_desc = get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV); 133 if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) { 134 error("invalid mmc device"); 135 fastboot_fail("invalid mmc device"); 136 return; 137 } 138 139 ret = get_partition_info_efi_by_name(dev_desc, cmd, &info); 140 if (ret) { 141 error("cannot find partition: '%s'", cmd); 142 fastboot_fail("cannot find partition"); 143 return; 144 } 145 146 /* Align blocks to erase group size to avoid erasing other partitions */ 147 grp_size = mmc->erase_grp_size; 148 blks_start = (info.start + grp_size - 1) & ~(grp_size - 1); 149 if (info.size >= grp_size) 150 blks_size = (info.size - (blks_start - info.start)) & 151 (~(grp_size - 1)); 152 else 153 blks_size = 0; 154 155 printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n", 156 blks_start, blks_start + blks_size); 157 158 blks = dev_desc->block_erase(dev_desc->dev, blks_start, blks_size); 159 if (blks != blks_size) { 160 error("failed erasing from device %d", dev_desc->dev); 161 fastboot_fail("failed erasing from device"); 162 return; 163 } 164 165 printf("........ erased " LBAFU " bytes from '%s'\n", 166 blks_size * info.blksz, cmd); 167 fastboot_okay(""); 168 } 169