blob: 52fc4f98847794a690a74b1cdf747254b8e7e99d [file] [log] [blame]
Channagoud Kadabi7768c462015-02-26 11:33:52 -08001/* Copyright (c) 2011-2013, 2015 The Linux Foundation. All rights reserved.
Kinson Chik66552a82011-03-29 15:59:06 -07002
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
Channagoud Kadabif73aa292013-01-31 16:55:20 -080012 * * Neither the name of The Linux Foundation. nor the names of its
Kinson Chik66552a82011-03-29 15:59:06 -070013 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <stdlib.h>
30#include <string.h>
vijay kumarc8c60a02015-04-28 13:05:04 +053031#include <crc32.h>
Kinson Chik66552a82011-03-29 15:59:06 -070032#include "mmc.h"
33#include "partition_parser.h"
vijay kumarc8c60a02015-04-28 13:05:04 +053034#define GPT_HEADER_SIZE 92
35#define GPT_LBA 1
36#define PARTITION_ENTRY_SIZE 128
37static bool flashing_gpt = 0;
38static bool parse_secondary_gpt = 0;
Kinson Chik66552a82011-03-29 15:59:06 -070039
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070040static uint32_t mmc_boot_read_gpt(uint32_t block_size);
41static uint32_t mmc_boot_read_mbr(uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070042static void mbr_fill_name(struct partition_entry *partition_ent,
43 uint32_t type);
44static uint32_t partition_verify_mbr_signature(uint32_t size,
45 uint8_t *buffer);
46static uint32_t mbr_partition_get_type(uint32_t size, uint8_t *partition,
47 uint32_t *partition_type);
48
49static uint32_t partition_get_type(uint32_t size, uint8_t *partition,
50 uint32_t *partition_type);
51static uint32_t partition_parse_gpt_header(uint8_t *buffer,
52 uint64_t *first_usable_lba,
53 uint32_t *partition_entry_size,
54 uint32_t *header_size,
55 uint32_t *max_partition_count);
56
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070057static uint32_t write_mbr(uint32_t, uint8_t *mbrImage, uint32_t block_size);
58static uint32_t write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070059
Ajay Dudanib01e5062011-12-03 23:23:42 -080060char *ext3_partitions[] =
61 { "system", "userdata", "persist", "cache", "tombstones" };
62char *vfat_partitions[] = { "modem", "mdm", "NONE" };
63
Kinson Chikf1a43512011-07-14 11:28:39 -070064unsigned int ext3_count = 0;
65unsigned int vfat_count = 0;
66
Channagoud Kadabie9b94022013-11-12 13:49:41 -080067struct partition_entry *partition_entries;
Pavel Nedevb5ba62d2013-07-22 11:57:41 +030068static unsigned gpt_partitions_exist = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -070069unsigned partition_count = 0;
70
Channagoud Kadabi0e332852013-04-19 12:55:53 -070071unsigned int partition_read_table()
Kinson Chikf1a43512011-07-14 11:28:39 -070072{
Ajay Dudanib01e5062011-12-03 23:23:42 -080073 unsigned int ret;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070074 uint32_t block_size;
75
76 block_size = mmc_get_device_blocksize();
Kinson Chikf1a43512011-07-14 11:28:39 -070077
Channagoud Kadabie9b94022013-11-12 13:49:41 -080078 /* Allocate partition entries array */
79 partition_entries = (struct partition_entry *) calloc(NUM_PARTITIONS, sizeof(struct partition_entry));
80 ASSERT(partition_entries);
81
Ajay Dudanib01e5062011-12-03 23:23:42 -080082 /* Read MBR of the card */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070083 ret = mmc_boot_read_mbr(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070084 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -080085 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -070086 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -080087 }
Kinson Chikf1a43512011-07-14 11:28:39 -070088
Ajay Dudanib01e5062011-12-03 23:23:42 -080089 /* Read GPT of the card if exist */
90 if (gpt_partitions_exist) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070091 ret = mmc_boot_read_gpt(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070092 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -080093 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -070094 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -080095 }
96 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -070097 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -070098}
99
100/*
101 * Read MBR from MMC card and fill partition table.
102 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700103static unsigned int mmc_boot_read_mbr(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700104{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700105 uint8_t *buffer = NULL;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800106 unsigned int dtype;
107 unsigned int dfirstsec;
108 unsigned int EBR_first_sec;
109 unsigned int EBR_current_sec;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700110 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800111 int idx, i;
Kinson Chikf1a43512011-07-14 11:28:39 -0700112
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700113 buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
114
115 if (!buffer)
116 {
117 dprintf(CRITICAL, "Error allocating memory while reading partition table\n");
118 ret = -1;
119 goto end;
120 }
121
Ajay Dudanib01e5062011-12-03 23:23:42 -0800122 /* Print out the MBR first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700123 ret = mmc_read(0, (unsigned int *)buffer, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800124 if (ret) {
125 dprintf(CRITICAL, "Could not read partition from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700126 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800127 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700128
Ajay Dudanib01e5062011-12-03 23:23:42 -0800129 /* Check to see if signature exists */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700130 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800131 if (ret) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700132 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800133 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700134
Ajay Dudanib01e5062011-12-03 23:23:42 -0800135 /*
136 * Process each of the four partitions in the MBR by reading the table
137 * information into our mbr table.
138 */
139 partition_count = 0;
140 idx = TABLE_ENTRY_0;
141 for (i = 0; i < 4; i++) {
142 /* Type 0xEE indicates end of MBR and GPT partitions exist */
143 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
144 if (dtype == MBR_PROTECTED_TYPE) {
145 gpt_partitions_exist = 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700146 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800147 }
148 partition_entries[partition_count].dtype = dtype;
149 partition_entries[partition_count].attribute_flag =
150 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
151 partition_entries[partition_count].first_lba =
152 GET_LWORD_FROM_BYTE(&buffer[idx +
153 i * TABLE_ENTRY_SIZE +
154 OFFSET_FIRST_SEC]);
155 partition_entries[partition_count].size =
156 GET_LWORD_FROM_BYTE(&buffer[idx +
157 i * TABLE_ENTRY_SIZE +
158 OFFSET_SIZE]);
159 dfirstsec = partition_entries[partition_count].first_lba;
160 mbr_fill_name(&partition_entries[partition_count],
161 partition_entries[partition_count].dtype);
162 partition_count++;
163 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700164 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800165 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700166
Ajay Dudanib01e5062011-12-03 23:23:42 -0800167 /* See if the last partition is EBR, if not, parsing is done */
168 if (dtype != MBR_EBR_TYPE) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700169 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800170 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700171
Ajay Dudanib01e5062011-12-03 23:23:42 -0800172 EBR_first_sec = dfirstsec;
173 EBR_current_sec = dfirstsec;
Kinson Chikf1a43512011-07-14 11:28:39 -0700174
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700175 ret = mmc_read((EBR_first_sec * block_size), (unsigned int *)buffer, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700176 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700177 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700178
Ajay Dudanib01e5062011-12-03 23:23:42 -0800179 /* Loop to parse the EBR */
180 for (i = 0;; i++) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700181 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800182 if (ret) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700183 ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800184 break;
185 }
186 partition_entries[partition_count].attribute_flag =
187 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
188 partition_entries[partition_count].dtype =
189 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
190 partition_entries[partition_count].first_lba =
191 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
192 OFFSET_FIRST_SEC]) +
193 EBR_current_sec;
194 partition_entries[partition_count].size =
195 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
196 mbr_fill_name(&(partition_entries[partition_count]),
197 partition_entries[partition_count].dtype);
198 partition_count++;
199 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700200 goto end;
Kinson Chikf1a43512011-07-14 11:28:39 -0700201
Ajay Dudanib01e5062011-12-03 23:23:42 -0800202 dfirstsec =
203 GET_LWORD_FROM_BYTE(&buffer
204 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
205 if (dfirstsec == 0) {
206 /* Getting to the end of the EBR tables */
207 break;
208 }
209 /* More EBR to follow - read in the next EBR sector */
210 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
211 + dfirstsec);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700212 ret = mmc_read(((EBR_first_sec + dfirstsec) * block_size),(unsigned int *)buffer,
213 block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700214 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700215 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700216
Ajay Dudanib01e5062011-12-03 23:23:42 -0800217 EBR_current_sec = EBR_first_sec + dfirstsec;
218 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700219end:
220 if (buffer)
221 free(buffer);
222
Ajay Dudanib01e5062011-12-03 23:23:42 -0800223 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700224}
Kinson Chik66552a82011-03-29 15:59:06 -0700225
226/*
227 * Read GPT from MMC and fill partition table
228 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700229static unsigned int mmc_boot_read_gpt(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700230{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700231 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800232 unsigned int header_size;
233 unsigned long long first_usable_lba;
234 unsigned long long backup_header_lba;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700235 unsigned long long card_size_sec;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800236 unsigned int max_partition_count = 0;
237 unsigned int partition_entry_size;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700238 unsigned int i = 0; /* Counter for each block */
239 unsigned int j = 0; /* Counter for each entry in a block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800240 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
241 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
242 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700243 unsigned long long partition_0;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700244 uint64_t device_density;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700245 uint8_t *data = NULL;
246 uint32_t part_entry_cnt = block_size / ENTRY_SIZE;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700247
Ajay Dudanib01e5062011-12-03 23:23:42 -0800248 partition_count = 0;
Kinson Chik66552a82011-03-29 15:59:06 -0700249
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700250 /* Get the density of the mmc device */
251
252 device_density = mmc_get_device_capacity();
253
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700254 data = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
255 if (!data)
256 {
257 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
258 ret = -1;
259 goto end;
260 }
261
Ajay Dudanib01e5062011-12-03 23:23:42 -0800262 /* Print out the GPT first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700263 ret = mmc_read(block_size, (unsigned int *)data, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700264 if (ret)
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700265 {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800266 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700267 goto end;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700268 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800269 ret = partition_parse_gpt_header(data, &first_usable_lba,
270 &partition_entry_size, &header_size,
271 &max_partition_count);
272 if (ret) {
273 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700274
Ajay Dudanib01e5062011-12-03 23:23:42 -0800275 /* Check the backup gpt */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700276
277 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700278 card_size_sec = (device_density) / block_size;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700279 ASSERT (card_size_sec > 0);
280
281 backup_header_lba = card_size_sec - 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700282 ret = mmc_read((backup_header_lba * block_size), (unsigned int *)data,
283 block_size);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700284
Ajay Dudanib01e5062011-12-03 23:23:42 -0800285 if (ret) {
286 dprintf(CRITICAL,
287 "GPT: Could not read backup gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700288 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800289 }
vijay kumarfe623342015-07-22 12:42:06 +0530290 parse_secondary_gpt = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800291 ret = partition_parse_gpt_header(data, &first_usable_lba,
292 &partition_entry_size,
293 &header_size,
294 &max_partition_count);
295 if (ret) {
296 dprintf(CRITICAL,
297 "GPT: Primary and backup signatures invalid\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700298 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800299 }
vijay kumarfe623342015-07-22 12:42:06 +0530300 parse_secondary_gpt = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800301 }
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700302 partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800303 /* Read GPT Entries */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700304 for (i = 0; i < (ROUNDUP(max_partition_count, part_entry_cnt)) / part_entry_cnt; i++) {
neetid6c38de12011-12-02 12:04:50 -0800305 ASSERT(partition_count < NUM_PARTITIONS);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700306 ret = mmc_read((partition_0 * block_size) + (i * block_size),
307 (uint32_t *) data, block_size);
Kinson Chik66552a82011-03-29 15:59:06 -0700308
Ajay Dudanib01e5062011-12-03 23:23:42 -0800309 if (ret) {
310 dprintf(CRITICAL,
311 "GPT: mmc read card failed reading partition entries.\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700312 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800313 }
Kinson Chik66552a82011-03-29 15:59:06 -0700314
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700315 for (j = 0; j < part_entry_cnt; j++) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800316 memcpy(&(partition_entries[partition_count].type_guid),
317 &data[(j * partition_entry_size)],
318 PARTITION_TYPE_GUID_SIZE);
319 if (partition_entries[partition_count].type_guid[0] ==
320 0x00
321 && partition_entries[partition_count].
322 type_guid[1] == 0x00) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700323 i = ROUNDUP(max_partition_count, part_entry_cnt);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800324 break;
325 }
326 memcpy(&
327 (partition_entries[partition_count].
328 unique_partition_guid),
329 &data[(j * partition_entry_size) +
330 UNIQUE_GUID_OFFSET],
331 UNIQUE_PARTITION_GUID_SIZE);
332 partition_entries[partition_count].first_lba =
333 GET_LLWORD_FROM_BYTE(&data
334 [(j * partition_entry_size) +
335 FIRST_LBA_OFFSET]);
336 partition_entries[partition_count].last_lba =
337 GET_LLWORD_FROM_BYTE(&data
338 [(j * partition_entry_size) +
339 LAST_LBA_OFFSET]);
340 partition_entries[partition_count].size =
341 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700342 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800343 partition_entries[partition_count].attribute_flag =
344 GET_LLWORD_FROM_BYTE(&data
345 [(j * partition_entry_size) +
346 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700347
Ajay Dudanib01e5062011-12-03 23:23:42 -0800348 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
349 memcpy(UTF16_name, &data[(j * partition_entry_size) +
350 PARTITION_NAME_OFFSET],
351 MAX_GPT_NAME_SIZE);
352 /*
353 * Currently partition names in *.xml are UTF-8 and lowercase
354 * Only supporting english for now so removing 2nd byte of UTF-16
355 */
356 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
357 partition_entries[partition_count].name[n] =
358 UTF16_name[n * 2];
359 }
360 partition_count++;
361 }
362 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700363end:
364 if (data)
365 free(data);
366
Ajay Dudanib01e5062011-12-03 23:23:42 -0800367 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700368}
369
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700370static unsigned int write_mbr_in_blocks(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700371{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800372 unsigned int dtype;
373 unsigned int dfirstsec;
374 unsigned int ebrSectorOffset;
375 unsigned char *ebrImage;
376 unsigned char *lastAddress;
377 int idx, i;
378 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700379
Ajay Dudanib01e5062011-12-03 23:23:42 -0800380 /* Write the first block */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700381 ret = mmc_write(0, block_size, (unsigned int *)mbrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800382 if (ret) {
383 dprintf(CRITICAL, "Failed to write mbr partition\n");
384 goto end;
385 }
386 dprintf(SPEW, "write of first MBR block ok\n");
387 /*
388 Loop through the MBR table to see if there is an EBR.
389 If found, then figure out where to write the first EBR
390 */
391 idx = TABLE_ENTRY_0;
392 for (i = 0; i < 4; i++) {
393 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
394 if (MBR_EBR_TYPE == dtype) {
395 dprintf(SPEW, "EBR found.\n");
396 break;
397 }
398 }
399 if (MBR_EBR_TYPE != dtype) {
400 dprintf(SPEW, "No EBR in this image\n");
401 goto end;
402 }
403 /* EBR exists. Write each EBR block to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700404 ebrImage = mbrImage + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800405 ebrSectorOffset =
406 GET_LWORD_FROM_BYTE(&mbrImage
407 [idx + i * TABLE_ENTRY_SIZE +
408 OFFSET_FIRST_SEC]);
409 dfirstsec = 0;
410 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
411 lastAddress = mbrImage + size;
412 while (ebrImage < lastAddress) {
413 dprintf(SPEW, "writing to 0x%X\n",
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700414 (ebrSectorOffset + dfirstsec) * block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800415 ret =
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700416 mmc_write((ebrSectorOffset + dfirstsec) * block_size,
417 block_size, (unsigned int *)ebrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800418 if (ret) {
419 dprintf(CRITICAL,
420 "Failed to write EBR block to sector 0x%X\n",
421 dfirstsec);
422 goto end;
423 }
424 dfirstsec =
425 GET_LWORD_FROM_BYTE(&ebrImage
426 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700427 ebrImage += block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800428 }
429 dprintf(INFO, "MBR written to mmc successfully\n");
430 end:
431 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700432}
433
434/* Write the MBR/EBR to the MMC. */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700435static unsigned int write_mbr(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700436{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800437 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700438
Ajay Dudanib01e5062011-12-03 23:23:42 -0800439 /* Verify that passed in block is a valid MBR */
440 ret = partition_verify_mbr_signature(size, mbrImage);
441 if (ret) {
442 goto end;
443 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700444
Ajay Dudanib01e5062011-12-03 23:23:42 -0800445 /* Write the MBR/EBR to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700446 ret = write_mbr_in_blocks(size, mbrImage, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800447 if (ret) {
448 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
449 goto end;
450 }
451 /* Re-read the MBR partition into mbr table */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700452 ret = mmc_boot_read_mbr(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800453 if (ret) {
454 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
455 goto end;
456 }
457 partition_dump();
458 end:
459 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700460}
461
462/*
463 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
464*/
465int reflect(int data, int len)
466{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800467 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700468
Ajay Dudanib01e5062011-12-03 23:23:42 -0800469 for (int i = 0; i < len; i++) {
470 if (data & 0x1) {
471 ref |= (1 << ((len - 1) - i));
472 }
473 data = (data >> 1);
474 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700475
Ajay Dudanib01e5062011-12-03 23:23:42 -0800476 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700477}
478
479/*
480* Function to calculate the CRC32
481*/
482unsigned int calculate_crc32(unsigned char *buffer, int len)
483{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800484 int byte_length = 8; /*length of unit (i.e. byte) */
485 int msb = 0;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700486 int polynomial = 0x04C11DB7; /* IEEE 32bit polynomial */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800487 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
488 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
489 int regs_msb = 0;
490 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700491
Ajay Dudanib01e5062011-12-03 23:23:42 -0800492 for (int i = 0; i < len; i++) {
493 int data_byte = buffer[i];
494 data_byte = reflect(data_byte, 8);
495 for (int j = 0; j < byte_length; j++) {
496 msb = data_byte >> (byte_length - 1); /* get MSB */
497 msb &= 1; /* ensure just 1 bit */
498 regs_msb = (regs >> 31) & 1; /* MSB of regs */
499 regs = regs << 1; /* shift regs for CRC-CCITT */
500 if (regs_msb ^ msb) { /* MSB is a 1 */
501 regs = regs ^ polynomial; /* XOR with generator poly */
502 }
503 regs = regs & regs_mask; /* Mask off excess upper bits */
504 data_byte <<= 1; /* get to next bit */
505 }
506 }
507 regs = regs & regs_mask;
508 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700509
Ajay Dudanib01e5062011-12-03 23:23:42 -0800510 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700511}
512
513/*
514 * Write the GPT Partition Entry Array to the MMC.
515 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800516static unsigned int
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700517write_gpt_partition_array(uint8_t *header,
518 uint32_t partition_array_start,
519 uint32_t array_size,
520 uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700521{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700522 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800523 unsigned long long partition_entry_lba;
524 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700525
Ajay Dudanib01e5062011-12-03 23:23:42 -0800526 partition_entry_lba =
527 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700528 partition_entry_array_start_location = partition_entry_lba * block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700529
Ajay Dudanib01e5062011-12-03 23:23:42 -0800530 ret = mmc_write(partition_entry_array_start_location, array_size,
531 (unsigned int *)partition_array_start);
532 if (ret) {
533 dprintf(CRITICAL,
534 "GPT: FAILED to write the partition entry array\n");
535 goto end;
536 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700537
Ajay Dudanib01e5062011-12-03 23:23:42 -0800538 end:
539 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700540}
541
Ajay Dudanib01e5062011-12-03 23:23:42 -0800542static void
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700543patch_gpt(uint8_t *gptImage, uint64_t density, uint32_t array_size,
544 uint32_t max_part_count, uint32_t part_entry_size, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700545{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800546 unsigned int partition_entry_array_start;
547 unsigned char *primary_gpt_header;
548 unsigned char *secondary_gpt_header;
549 unsigned int offset;
550 unsigned long long card_size_sec;
551 int total_part = 0;
552 unsigned int last_part_offset;
553 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700554
Ajay Dudanib01e5062011-12-03 23:23:42 -0800555 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700556 card_size_sec = (density) / block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800557 /* Working around cap at 4GB */
558 if (card_size_sec == 0) {
559 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
560 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700561
Ajay Dudanib01e5062011-12-03 23:23:42 -0800562 /* Patching primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700563 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800564 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
565 ((long long)(card_size_sec - 1)));
566 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
567 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700568
Ajay Dudanib01e5062011-12-03 23:23:42 -0800569 /* Patching backup GPT */
570 offset = (2 * array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700571 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800572 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
573 ((long long)(card_size_sec - 1)));
574 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
575 ((long long)(card_size_sec - 34)));
576 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
577 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700578
Ajay Dudanib01e5062011-12-03 23:23:42 -0800579 /* Find last partition */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700580 while (*(primary_gpt_header + block_size + total_part * ENTRY_SIZE) !=
Ajay Dudanib01e5062011-12-03 23:23:42 -0800581 0) {
582 total_part++;
583 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700584
Ajay Dudanib01e5062011-12-03 23:23:42 -0800585 /* Patching last partition */
586 last_part_offset =
587 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700588 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800589 (long long)(card_size_sec - 34));
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700590 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800591 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700592
Ajay Dudanib01e5062011-12-03 23:23:42 -0800593 /* Updating CRC of the Partition entry array in both headers */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700594 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800595 crc_value = calculate_crc32(partition_entry_array_start,
596 max_part_count * part_entry_size);
597 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700598
Ajay Dudanib01e5062011-12-03 23:23:42 -0800599 crc_value = calculate_crc32(partition_entry_array_start + array_size,
600 max_part_count * part_entry_size);
601 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700602
Ajay Dudanib01e5062011-12-03 23:23:42 -0800603 /* Clearing CRC fields to calculate */
604 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
605 crc_value = calculate_crc32(primary_gpt_header, 92);
606 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700607
Ajay Dudanib01e5062011-12-03 23:23:42 -0800608 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
609 crc_value = (calculate_crc32(secondary_gpt_header, 92));
610 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700611
612}
613
614/*
615 * Write the GPT to the MMC.
616 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700617static unsigned int write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700618{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700619 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800620 unsigned int header_size;
621 unsigned long long first_usable_lba;
622 unsigned long long backup_header_lba;
623 unsigned int max_partition_count = 0;
624 unsigned int partition_entry_size;
625 unsigned int partition_entry_array_start;
626 unsigned char *primary_gpt_header;
627 unsigned char *secondary_gpt_header;
628 unsigned int offset;
629 unsigned int partition_entry_array_size;
630 unsigned long long primary_header_location; /* address on the emmc card */
631 unsigned long long secondary_header_location; /* address on the emmc card */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700632 uint64_t device_density;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700633
Ajay Dudanib01e5062011-12-03 23:23:42 -0800634 /* Verify that passed block has a valid GPT primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700635 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800636 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
637 &partition_entry_size, &header_size,
638 &max_partition_count);
639 if (ret) {
640 dprintf(CRITICAL,
641 "GPT: Primary signature invalid cannot write GPT\n");
642 goto end;
643 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700644
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700645 /* Get the density of the mmc device */
646
647 device_density = mmc_get_device_capacity();
648
Ajay Dudanib01e5062011-12-03 23:23:42 -0800649 /* Verify that passed block has a valid backup GPT HEADER */
650 partition_entry_array_size = partition_entry_size * max_partition_count;
651 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
652 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
653 }
654 offset = (2 * partition_entry_array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700655 secondary_gpt_header = offset + block_size + primary_gpt_header;
vijay kumarc8c60a02015-04-28 13:05:04 +0530656 parse_secondary_gpt = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800657 ret =
658 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
659 &partition_entry_size, &header_size,
660 &max_partition_count);
vijay kumarc8c60a02015-04-28 13:05:04 +0530661 parse_secondary_gpt = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800662 if (ret) {
663 dprintf(CRITICAL,
664 "GPT: Backup signature invalid cannot write GPT\n");
665 goto end;
666 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700667
Ajay Dudanib01e5062011-12-03 23:23:42 -0800668 /* Patching the primary and the backup header of the GPT table */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700669 patch_gpt(gptImage, device_density, partition_entry_array_size,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700670 max_partition_count, partition_entry_size, block_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700671
Ajay Dudanib01e5062011-12-03 23:23:42 -0800672 /* Erasing the eMMC card before writing */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700673 ret = mmc_erase_card(0x00000000, device_density);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800674 if (ret) {
675 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
676 goto end;
677 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700678
Ajay Dudanib01e5062011-12-03 23:23:42 -0800679 /* Writing protective MBR */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700680 ret = mmc_write(0, block_size, (unsigned int *)gptImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800681 if (ret) {
682 dprintf(CRITICAL, "Failed to write Protective MBR\n");
683 goto end;
684 }
685 /* Writing the primary GPT header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700686 primary_header_location = block_size;
687 ret = mmc_write(primary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800688 (unsigned int *)primary_gpt_header);
689 if (ret) {
690 dprintf(CRITICAL, "Failed to write GPT header\n");
691 goto end;
692 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700693
Ajay Dudanib01e5062011-12-03 23:23:42 -0800694 /* Writing the backup GPT header */
695 backup_header_lba = GET_LLWORD_FROM_BYTE
696 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700697 secondary_header_location = backup_header_lba * block_size;
698 ret = mmc_write(secondary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800699 (unsigned int *)secondary_gpt_header);
700 if (ret) {
701 dprintf(CRITICAL, "Failed to write GPT backup header\n");
702 goto end;
703 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700704
Ajay Dudanib01e5062011-12-03 23:23:42 -0800705 /* Writing the partition entries array for the primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700706 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800707 ret = write_gpt_partition_array(primary_gpt_header,
708 partition_entry_array_start,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700709 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800710 if (ret) {
711 dprintf(CRITICAL,
712 "GPT: Could not write GPT Partition entries array\n");
713 goto end;
714 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700715
Ajay Dudanib01e5062011-12-03 23:23:42 -0800716 /*Writing the partition entries array for the backup header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700717 partition_entry_array_start = primary_gpt_header + block_size +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800718 partition_entry_array_size;
719 ret = write_gpt_partition_array(secondary_gpt_header,
720 partition_entry_array_start,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700721 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800722 if (ret) {
723 dprintf(CRITICAL,
724 "GPT: Could not write GPT Partition entries array\n");
725 goto end;
726 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700727
Ajay Dudanib01e5062011-12-03 23:23:42 -0800728 /* Re-read the GPT partition table */
729 dprintf(INFO, "Re-reading the GPT Partition Table\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700730 ret = mmc_boot_read_gpt(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800731 if (ret) {
732 dprintf(CRITICAL,
733 "GPT: Failure to re- read the GPT Partition table\n");
734 goto end;
735 }
vijay kumarc8c60a02015-04-28 13:05:04 +0530736 flashing_gpt = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800737 partition_dump();
738 dprintf(CRITICAL, "GPT: Partition Table written\n");
739 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700740
Ajay Dudanib01e5062011-12-03 23:23:42 -0800741 end:
742 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700743}
744
Ajay Dudanib01e5062011-12-03 23:23:42 -0800745unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700746{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700747 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800748 unsigned int partition_type;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700749 uint32_t block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700750
Ajay Dudanib01e5062011-12-03 23:23:42 -0800751 if (partition == 0) {
752 dprintf(CRITICAL, "NULL partition\n");
753 goto end;
754 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700755
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700756 block_size = mmc_get_device_blocksize();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800757 ret = partition_get_type(size, partition, &partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700758 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800759 goto end;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700760
Ajay Dudanib01e5062011-12-03 23:23:42 -0800761 switch (partition_type) {
762 case PARTITION_TYPE_MBR:
763 dprintf(INFO, "Writing MBR partition\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700764 ret = write_mbr(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800765 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700766
Ajay Dudanib01e5062011-12-03 23:23:42 -0800767 case PARTITION_TYPE_GPT:
768 dprintf(INFO, "Writing GPT partition\n");
vijay kumarc8c60a02015-04-28 13:05:04 +0530769 flashing_gpt = 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700770 ret = write_gpt(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800771 dprintf(CRITICAL, "Re-Flash all the partitions\n");
772 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700773
Ajay Dudanib01e5062011-12-03 23:23:42 -0800774 default:
775 dprintf(CRITICAL, "Invalid partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700776 ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800777 goto end;
778 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700779
Ajay Dudanib01e5062011-12-03 23:23:42 -0800780 end:
781 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700782}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800783
Kinson Chikf1a43512011-07-14 11:28:39 -0700784/*
785 * Fill name for android partition found.
786 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800787static void
788mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700789{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800790 switch (type) {
791 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
792 case MBR_MODEM_TYPE:
793 case MBR_MODEM_TYPE2:
794 /* if already assigned last name available then return */
795 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
796 return;
797 strlcpy((char *)partition_ent->name,
798 (const char *)vfat_partitions[vfat_count],
799 sizeof(partition_ent->name));
800 vfat_count++;
801 break;
802 case MBR_SBL1_TYPE:
803 memcpy(partition_ent->name, "sbl1", 4);
804 break;
805 case MBR_SBL2_TYPE:
806 memcpy(partition_ent->name, "sbl2", 4);
807 break;
808 case MBR_SBL3_TYPE:
809 memcpy(partition_ent->name, "sbl3", 4);
810 break;
811 case MBR_RPM_TYPE:
812 memcpy(partition_ent->name, "rpm", 3);
813 break;
814 case MBR_TZ_TYPE:
815 memcpy(partition_ent->name, "tz", 2);
816 break;
817 case MBR_ABOOT_TYPE:
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530818#if PLATFORM_MSM7X27A
819 memcpy(partition_ent->name, "FOTA", 4);
820#else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800821 memcpy(partition_ent->name, "aboot", 5);
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530822#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -0800823 break;
824 case MBR_BOOT_TYPE:
825 memcpy(partition_ent->name, "boot", 4);
826 break;
827 case MBR_MODEM_ST1_TYPE:
828 memcpy(partition_ent->name, "modem_st1", 9);
829 break;
830 case MBR_MODEM_ST2_TYPE:
831 memcpy(partition_ent->name, "modem_st2", 9);
832 break;
833 case MBR_EFS2_TYPE:
834 memcpy(partition_ent->name, "efs2", 4);
835 break;
836 case MBR_USERDATA_TYPE:
837 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
838 return;
839 strlcpy((char *)partition_ent->name,
840 (const char *)ext3_partitions[ext3_count],
841 sizeof(partition_ent->name));
842 ext3_count++;
843 break;
844 case MBR_RECOVERY_TYPE:
845 memcpy(partition_ent->name, "recovery", 8);
846 break;
847 case MBR_MISC_TYPE:
848 memcpy(partition_ent->name, "misc", 4);
849 break;
Neeti Desai2d6b0e42012-03-23 15:48:57 -0700850 case MBR_SSD_TYPE:
851 memcpy(partition_ent->name, "ssd", 3);
852 break;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800853 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700854}
855
856/*
857 * Find index of parition in array of partition entries
858 */
Pavel Nedev285ad922013-04-26 10:39:19 +0300859int partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700860{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800861 unsigned int input_string_length = strlen(name);
862 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700863
neetid6c38de12011-12-02 12:04:50 -0800864 if( partition_count >= NUM_PARTITIONS)
865 {
866 return INVALID_PTN;
867 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800868 for (n = 0; n < partition_count; n++) {
Channagoud Kadabi7768c462015-02-26 11:33:52 -0800869 if ((input_string_length == strlen((const char *)&partition_entries[n].name))
870 && !memcmp(name, &partition_entries[n].name, input_string_length)) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800871 return n;
872 }
873 }
874 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700875}
876
877/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800878unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700879{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700880 uint32_t block_size;
881
882 block_size = mmc_get_device_blocksize();
883
Ajay Dudanib01e5062011-12-03 23:23:42 -0800884 if (index == INVALID_PTN)
885 return 0;
886 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700887 return partition_entries[index].size * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800888 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700889}
890
891/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800892unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700893{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700894 uint32_t block_size;
895
896 block_size = mmc_get_device_blocksize();
897
Ajay Dudanib01e5062011-12-03 23:23:42 -0800898 if (index == INVALID_PTN)
899 return 0;
900 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700901 return partition_entries[index].first_lba * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800902 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700903}
904
905/* Debug: Print all parsed partitions */
906void partition_dump()
907{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800908 unsigned i = 0;
909 for (i = 0; i < partition_count; i++) {
910 dprintf(SPEW,
911 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
912 i, partition_entries[i].name, partition_entries[i].size,
913 partition_entries[i].dtype,
914 partition_entries[i].first_lba,
915 partition_entries[i].last_lba);
916 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700917}
918
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700919static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800920partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700921{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800922 /* Avoid checking past end of buffer */
923 if ((TABLE_SIGNATURE + 1) > size) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700924 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800925 }
926 /* Check to see if signature exists */
927 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
928 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
929 dprintf(CRITICAL, "MBR signature does not match.\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700930 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800931 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700932 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700933}
934
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700935static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800936mbr_partition_get_type(unsigned size, unsigned char *partition,
937 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700938{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800939 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700940
Channagoud Kadabi1921eba2015-03-12 15:14:22 -0700941 if (size < (type_offset + sizeof (*partition_type))) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800942 goto end;
943 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700944
Ajay Dudanib01e5062011-12-03 23:23:42 -0800945 *partition_type = partition[type_offset];
946 end:
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700947 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700948}
949
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700950static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800951partition_get_type(unsigned size, unsigned char *partition,
952 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700953{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700954 unsigned int ret = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700955
Ajay Dudanib01e5062011-12-03 23:23:42 -0800956 /*
957 * If the block contains the MBR signature, then it's likely either
958 * MBR or MBR with protective type (GPT). If the MBR signature is
959 * not there, then it could be the GPT backup.
960 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700961
Ajay Dudanib01e5062011-12-03 23:23:42 -0800962 /* First check the MBR signature */
963 ret = partition_verify_mbr_signature(size, partition);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700964 if (!ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800965 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -0700966
Ajay Dudanib01e5062011-12-03 23:23:42 -0800967 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
968 ret =
969 mbr_partition_get_type(size, partition,
970 &mbr_partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700971 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800972 dprintf(CRITICAL, "Cannot get TYPE of partition");
973 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
974 *partition_type = PARTITION_TYPE_GPT;
975 } else {
976 *partition_type = PARTITION_TYPE_MBR;
977 }
978 } else {
979 /*
980 * This could be the GPT backup. Make that assumption for now.
981 * Anybody who treats the block as GPT backup should check the
982 * signature.
983 */
984 *partition_type = PARTITION_TYPE_GPT_BACKUP;
985 }
986 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700987}
Kinson Chik4d7444f2011-09-13 15:48:51 -0700988
989/*
990 * Parse the gpt header and get the required header fields
991 * Return 0 on valid signature
992 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700993static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800994partition_parse_gpt_header(unsigned char *buffer,
995 unsigned long long *first_usable_lba,
996 unsigned int *partition_entry_size,
997 unsigned int *header_size,
998 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -0700999{
vijay kumarc8c60a02015-04-28 13:05:04 +05301000 uint32_t crc_val_org = 0;
1001 uint32_t crc_val = 0;
1002 uint32_t ret = 0;
1003 uint32_t partitions_for_block = 0;
1004 uint32_t blocks_to_read = 0;
1005 unsigned char *new_buffer = NULL;
1006 unsigned long long last_usable_lba = 0;
1007 unsigned long long partition_0 = 0;
1008 unsigned long long current_lba = 0;
1009 uint32_t block_size = mmc_get_device_blocksize();
1010 /* Get the density of the mmc device */
1011 uint64_t device_density = mmc_get_device_capacity();
1012
Ajay Dudanib01e5062011-12-03 23:23:42 -08001013 /* Check GPT Signature */
1014 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
1015 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
1016 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001017
Ajay Dudanib01e5062011-12-03 23:23:42 -08001018 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
vijay kumarc8c60a02015-04-28 13:05:04 +05301019 /*check for header size too small*/
1020 if (*header_size < GPT_HEADER_SIZE) {
1021 dprintf(CRITICAL,"GPT Header size is too small\n");
1022 return 1;
1023 }
1024 /*check for header size too large*/
1025 if (*header_size > block_size) {
1026 dprintf(CRITICAL,"GPT Header size is too large\n");
1027 return 1;
1028 }
1029
1030 crc_val_org = GET_LWORD_FROM_BYTE(&buffer[HEADER_CRC_OFFSET]);
1031 /*Write CRC to 0 before we calculate the crc of the GPT header*/
1032 crc_val = 0;
1033 PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);
1034
1035 crc_val = crc32(~0L,buffer, *header_size) ^ (~0L);
1036 if (crc_val != crc_val_org) {
1037 dprintf(CRITICAL,"Header crc mismatch crc_val = %u with crc_val_org = %u\n", crc_val,crc_val_org);
1038 return 1;
1039 }
1040 else
1041 PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);
1042
1043 current_lba =
1044 GET_LLWORD_FROM_BYTE(&buffer[PRIMARY_HEADER_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -08001045 *first_usable_lba =
1046 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
1047 *max_partition_count =
1048 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
1049 *partition_entry_size =
1050 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
vijay kumarc8c60a02015-04-28 13:05:04 +05301051 last_usable_lba =
1052 GET_LLWORD_FROM_BYTE(&buffer[LAST_USABLE_LBA_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -07001053
vijay kumarc8c60a02015-04-28 13:05:04 +05301054 /*current lba and GPT lba should be same*/
1055 if (!parse_secondary_gpt) {
1056 if (current_lba != GPT_LBA) {
1057 dprintf(CRITICAL,"GPT first usable LBA mismatch\n");
1058 return 1;
1059 }
1060 }
1061 /*check for first lba should be with in the valid range*/
1062 if (*first_usable_lba > (device_density/block_size)) {
1063 dprintf(CRITICAL,"Invalid first_usable_lba\n");
1064 return 1;
1065 }
1066 /*check for last lba should be with in the valid range*/
1067 if (last_usable_lba > (device_density/block_size)) {
1068 dprintf(CRITICAL,"Invalid last_usable_lba\n");
1069 return 1;
1070 }
1071 /*check for partition entry size*/
1072 if (*partition_entry_size != PARTITION_ENTRY_SIZE) {
1073 dprintf(CRITICAL,"Invalid parition entry size\n");
1074 return 1;
1075 }
1076
1077 if ((*max_partition_count) > (MIN_PARTITION_ARRAY_SIZE /(*partition_entry_size))) {
1078 dprintf(CRITICAL, "Invalid maximum partition count\n");
1079 return 1;
1080 }
1081
1082 partitions_for_block = block_size / (*partition_entry_size);
1083
1084 blocks_to_read = (*max_partition_count)/ partitions_for_block;
1085 if ((*max_partition_count) % partitions_for_block) {
1086 blocks_to_read += 1;
1087 }
1088
1089 new_buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP((blocks_to_read * block_size),CACHE_LINE));
1090
1091 if (!new_buffer)
1092 {
1093 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
1094 return 1;
1095 }
1096
1097 if (!flashing_gpt) {
1098 partition_0 = GET_LLWORD_FROM_BYTE(&buffer[PARTITION_ENTRIES_OFFSET]);
1099 /*start LBA should always be 2 in primary GPT*/
1100 if(partition_0 != 0x2) {
1101 dprintf(CRITICAL, "Starting LBA mismatch\n");
1102 goto fail;
1103
1104 }
1105 /*read the partition entries to new_buffer*/
1106 ret = mmc_read((partition_0) * (block_size), (unsigned int *)new_buffer, (blocks_to_read * block_size));
1107 if (ret)
1108 {
1109 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
1110 goto fail;
1111 }
1112 crc_val_org = GET_LWORD_FROM_BYTE(&buffer[PARTITION_CRC_OFFSET]);
1113
1114 crc_val = crc32(~0L,new_buffer, ((*max_partition_count) * (*partition_entry_size))) ^ (~0L);
1115 if (crc_val != crc_val_org) {
1116 dprintf(CRITICAL,"Partition entires crc mismatch crc_val= %u with crc_val_org= %u\n",crc_val,crc_val_org);
1117 ret = 1;
1118 }
1119 }
1120fail:
1121 free(new_buffer);
1122 return ret;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001123}
Pavel Nedevb5ba62d2013-07-22 11:57:41 +03001124
1125bool partition_gpt_exists()
1126{
1127 return (gpt_partitions_exist != 0);
1128}