blob: 22be711804bb4f458e9d5d0cb55da661fcf17580 [file] [log] [blame]
Vijay Kumar Pendoti17c38532016-05-04 20:27:52 +05301/* Copyright (c) 2011-2016, 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 kumar24c9ed12015-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 kumar24c9ed12015-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;
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -080039__WEAK void mmc_set_lun(uint8_t lun)
40{
41}
42
43__WEAK uint8_t mmc_get_lun(void)
44{
45 return 0;
46}
47
48__WEAK void mmc_read_partition_table(uint8_t arg)
49{
50 if(partition_read_table())
51 {
52 dprintf(CRITICAL, "Error reading the partition table info\n");
53 ASSERT(0);
54 }
55}
56
Channagoud Kadabi96c629e2013-09-10 14:21:30 -070057static uint32_t mmc_boot_read_gpt(uint32_t block_size);
58static uint32_t mmc_boot_read_mbr(uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070059static void mbr_fill_name(struct partition_entry *partition_ent,
60 uint32_t type);
61static uint32_t partition_verify_mbr_signature(uint32_t size,
62 uint8_t *buffer);
63static uint32_t mbr_partition_get_type(uint32_t size, uint8_t *partition,
64 uint32_t *partition_type);
65
66static uint32_t partition_get_type(uint32_t size, uint8_t *partition,
67 uint32_t *partition_type);
68static uint32_t partition_parse_gpt_header(uint8_t *buffer,
69 uint64_t *first_usable_lba,
70 uint32_t *partition_entry_size,
71 uint32_t *header_size,
72 uint32_t *max_partition_count);
73
Channagoud Kadabi96c629e2013-09-10 14:21:30 -070074static uint32_t write_mbr(uint32_t, uint8_t *mbrImage, uint32_t block_size);
75static uint32_t write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070076
Ajay Dudanib01e5062011-12-03 23:23:42 -080077char *ext3_partitions[] =
78 { "system", "userdata", "persist", "cache", "tombstones" };
79char *vfat_partitions[] = { "modem", "mdm", "NONE" };
80
Kinson Chikf1a43512011-07-14 11:28:39 -070081unsigned int ext3_count = 0;
82unsigned int vfat_count = 0;
83
Channagoud Kadabie9cb1c22013-11-12 13:49:41 -080084struct partition_entry *partition_entries;
Pavel Nedevb5ba62d2013-07-22 11:57:41 +030085static unsigned gpt_partitions_exist = 0;
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -080086static unsigned partition_count;
Kinson Chikf1a43512011-07-14 11:28:39 -070087
Channagoud Kadabi0e332852013-04-19 12:55:53 -070088unsigned int partition_read_table()
Kinson Chikf1a43512011-07-14 11:28:39 -070089{
Ajay Dudanib01e5062011-12-03 23:23:42 -080090 unsigned int ret;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -070091 uint32_t block_size;
92
93 block_size = mmc_get_device_blocksize();
Kinson Chikf1a43512011-07-14 11:28:39 -070094
Channagoud Kadabie9cb1c22013-11-12 13:49:41 -080095 /* Allocate partition entries array */
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -080096 if(!partition_entries)
97 {
98 partition_entries = (struct partition_entry *) calloc(NUM_PARTITIONS, sizeof(struct partition_entry));
99 ASSERT(partition_entries);
100 }
Channagoud Kadabie9cb1c22013-11-12 13:49:41 -0800101
Ajay Dudanib01e5062011-12-03 23:23:42 -0800102 /* Read MBR of the card */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700103 ret = mmc_boot_read_mbr(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700104 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800105 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700106 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800107 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700108
Ajay Dudanib01e5062011-12-03 23:23:42 -0800109 /* Read GPT of the card if exist */
110 if (gpt_partitions_exist) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700111 ret = mmc_boot_read_gpt(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700112 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800113 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700114 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800115 }
116 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700117 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700118}
119
120/*
121 * Read MBR from MMC card and fill partition table.
122 */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700123static unsigned int mmc_boot_read_mbr(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700124{
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700125 uint8_t *buffer = NULL;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800126 unsigned int dtype;
127 unsigned int dfirstsec;
128 unsigned int EBR_first_sec;
129 unsigned int EBR_current_sec;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700130 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800131 int idx, i;
Kinson Chikf1a43512011-07-14 11:28:39 -0700132
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700133 buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
134
135 if (!buffer)
136 {
137 dprintf(CRITICAL, "Error allocating memory while reading partition table\n");
138 ret = -1;
139 goto end;
140 }
141
Ajay Dudanib01e5062011-12-03 23:23:42 -0800142 /* Print out the MBR first */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700143 ret = mmc_read(0, (unsigned int *)buffer, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800144 if (ret) {
145 dprintf(CRITICAL, "Could not read partition from mmc\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700146 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800147 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700148
Ajay Dudanib01e5062011-12-03 23:23:42 -0800149 /* Check to see if signature exists */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700150 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800151 if (ret) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700152 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800153 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700154
Ajay Dudanib01e5062011-12-03 23:23:42 -0800155 /*
156 * Process each of the four partitions in the MBR by reading the table
157 * information into our mbr table.
158 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800159 idx = TABLE_ENTRY_0;
160 for (i = 0; i < 4; i++) {
161 /* Type 0xEE indicates end of MBR and GPT partitions exist */
162 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
163 if (dtype == MBR_PROTECTED_TYPE) {
164 gpt_partitions_exist = 1;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700165 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800166 }
167 partition_entries[partition_count].dtype = dtype;
168 partition_entries[partition_count].attribute_flag =
169 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
170 partition_entries[partition_count].first_lba =
171 GET_LWORD_FROM_BYTE(&buffer[idx +
172 i * TABLE_ENTRY_SIZE +
173 OFFSET_FIRST_SEC]);
174 partition_entries[partition_count].size =
175 GET_LWORD_FROM_BYTE(&buffer[idx +
176 i * TABLE_ENTRY_SIZE +
177 OFFSET_SIZE]);
178 dfirstsec = partition_entries[partition_count].first_lba;
179 mbr_fill_name(&partition_entries[partition_count],
180 partition_entries[partition_count].dtype);
181 partition_count++;
182 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700183 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800184 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700185
Ajay Dudanib01e5062011-12-03 23:23:42 -0800186 /* See if the last partition is EBR, if not, parsing is done */
187 if (dtype != MBR_EBR_TYPE) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700188 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800189 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700190
Ajay Dudanib01e5062011-12-03 23:23:42 -0800191 EBR_first_sec = dfirstsec;
192 EBR_current_sec = dfirstsec;
Kinson Chikf1a43512011-07-14 11:28:39 -0700193
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700194 ret = mmc_read((EBR_first_sec * block_size), (unsigned int *)buffer, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700195 if (ret)
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700196 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700197
Ajay Dudanib01e5062011-12-03 23:23:42 -0800198 /* Loop to parse the EBR */
199 for (i = 0;; i++) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700200 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800201 if (ret) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700202 ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800203 break;
204 }
205 partition_entries[partition_count].attribute_flag =
206 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
207 partition_entries[partition_count].dtype =
208 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
209 partition_entries[partition_count].first_lba =
210 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
211 OFFSET_FIRST_SEC]) +
212 EBR_current_sec;
213 partition_entries[partition_count].size =
214 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
215 mbr_fill_name(&(partition_entries[partition_count]),
216 partition_entries[partition_count].dtype);
217 partition_count++;
218 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700219 goto end;
Kinson Chikf1a43512011-07-14 11:28:39 -0700220
Ajay Dudanib01e5062011-12-03 23:23:42 -0800221 dfirstsec =
222 GET_LWORD_FROM_BYTE(&buffer
223 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
224 if (dfirstsec == 0) {
225 /* Getting to the end of the EBR tables */
226 break;
227 }
228 /* More EBR to follow - read in the next EBR sector */
229 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
230 + dfirstsec);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700231 ret = mmc_read(((EBR_first_sec + dfirstsec) * block_size),(unsigned int *)buffer,
232 block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700233 if (ret)
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700234 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700235
Ajay Dudanib01e5062011-12-03 23:23:42 -0800236 EBR_current_sec = EBR_first_sec + dfirstsec;
237 }
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700238end:
239 if (buffer)
240 free(buffer);
241
Ajay Dudanib01e5062011-12-03 23:23:42 -0800242 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700243}
Kinson Chik66552a82011-03-29 15:59:06 -0700244
245/*
246 * Read GPT from MMC and fill partition table
247 */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700248static unsigned int mmc_boot_read_gpt(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700249{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700250 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800251 unsigned int header_size;
252 unsigned long long first_usable_lba;
253 unsigned long long backup_header_lba;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700254 unsigned long long card_size_sec;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800255 unsigned int max_partition_count = 0;
256 unsigned int partition_entry_size;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700257 unsigned int i = 0; /* Counter for each block */
258 unsigned int j = 0; /* Counter for each entry in a block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800259 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
260 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
261 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700262 unsigned long long partition_0;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700263 uint64_t device_density;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700264 uint8_t *data = NULL;
265 uint32_t part_entry_cnt = block_size / ENTRY_SIZE;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700266
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700267 /* Get the density of the mmc device */
268
269 device_density = mmc_get_device_capacity();
270
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700271 data = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
272 if (!data)
273 {
274 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
275 ret = -1;
276 goto end;
277 }
278
Ajay Dudanib01e5062011-12-03 23:23:42 -0800279 /* Print out the GPT first */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700280 ret = mmc_read(block_size, (unsigned int *)data, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700281 if (ret)
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700282 {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800283 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700284 goto end;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700285 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800286 ret = partition_parse_gpt_header(data, &first_usable_lba,
287 &partition_entry_size, &header_size,
288 &max_partition_count);
289 if (ret) {
290 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700291
Ajay Dudanib01e5062011-12-03 23:23:42 -0800292 /* Check the backup gpt */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700293
294 /* Get size of MMC */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700295 card_size_sec = (device_density) / block_size;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700296 ASSERT (card_size_sec > 0);
297
298 backup_header_lba = card_size_sec - 1;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700299 ret = mmc_read((backup_header_lba * block_size), (unsigned int *)data,
300 block_size);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700301
Ajay Dudanib01e5062011-12-03 23:23:42 -0800302 if (ret) {
303 dprintf(CRITICAL,
304 "GPT: Could not read backup gpt from mmc\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700305 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800306 }
vijay kumared75ae42015-07-22 12:42:06 +0530307 parse_secondary_gpt = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800308 ret = partition_parse_gpt_header(data, &first_usable_lba,
309 &partition_entry_size,
310 &header_size,
311 &max_partition_count);
312 if (ret) {
313 dprintf(CRITICAL,
314 "GPT: Primary and backup signatures invalid\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700315 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800316 }
vijay kumared75ae42015-07-22 12:42:06 +0530317 parse_secondary_gpt = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800318 }
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700319 partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800320 /* Read GPT Entries */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700321 for (i = 0; i < (ROUNDUP(max_partition_count, part_entry_cnt)) / part_entry_cnt; i++) {
neetid6c38de12011-12-02 12:04:50 -0800322 ASSERT(partition_count < NUM_PARTITIONS);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700323 ret = mmc_read((partition_0 * block_size) + (i * block_size),
324 (uint32_t *) data, block_size);
Kinson Chik66552a82011-03-29 15:59:06 -0700325
Ajay Dudanib01e5062011-12-03 23:23:42 -0800326 if (ret) {
327 dprintf(CRITICAL,
328 "GPT: mmc read card failed reading partition entries.\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700329 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800330 }
Kinson Chik66552a82011-03-29 15:59:06 -0700331
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700332 for (j = 0; j < part_entry_cnt; j++) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800333 memcpy(&(partition_entries[partition_count].type_guid),
334 &data[(j * partition_entry_size)],
335 PARTITION_TYPE_GUID_SIZE);
336 if (partition_entries[partition_count].type_guid[0] ==
337 0x00
338 && partition_entries[partition_count].
339 type_guid[1] == 0x00) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700340 i = ROUNDUP(max_partition_count, part_entry_cnt);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800341 break;
342 }
343 memcpy(&
344 (partition_entries[partition_count].
345 unique_partition_guid),
346 &data[(j * partition_entry_size) +
347 UNIQUE_GUID_OFFSET],
348 UNIQUE_PARTITION_GUID_SIZE);
349 partition_entries[partition_count].first_lba =
350 GET_LLWORD_FROM_BYTE(&data
351 [(j * partition_entry_size) +
352 FIRST_LBA_OFFSET]);
353 partition_entries[partition_count].last_lba =
354 GET_LLWORD_FROM_BYTE(&data
355 [(j * partition_entry_size) +
356 LAST_LBA_OFFSET]);
357 partition_entries[partition_count].size =
358 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700359 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800360 partition_entries[partition_count].attribute_flag =
361 GET_LLWORD_FROM_BYTE(&data
362 [(j * partition_entry_size) +
363 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700364
Ajay Dudanib01e5062011-12-03 23:23:42 -0800365 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
366 memcpy(UTF16_name, &data[(j * partition_entry_size) +
367 PARTITION_NAME_OFFSET],
368 MAX_GPT_NAME_SIZE);
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -0800369 partition_entries[partition_count].lun = mmc_get_lun();
370
Ajay Dudanib01e5062011-12-03 23:23:42 -0800371 /*
372 * Currently partition names in *.xml are UTF-8 and lowercase
373 * Only supporting english for now so removing 2nd byte of UTF-16
374 */
375 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
376 partition_entries[partition_count].name[n] =
377 UTF16_name[n * 2];
378 }
379 partition_count++;
380 }
381 }
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700382end:
383 if (data)
384 free(data);
385
Ajay Dudanib01e5062011-12-03 23:23:42 -0800386 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700387}
388
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700389static unsigned int write_mbr_in_blocks(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700390{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800391 unsigned int dtype;
392 unsigned int dfirstsec;
393 unsigned int ebrSectorOffset;
394 unsigned char *ebrImage;
395 unsigned char *lastAddress;
396 int idx, i;
397 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700398
Ajay Dudanib01e5062011-12-03 23:23:42 -0800399 /* Write the first block */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700400 ret = mmc_write(0, block_size, (unsigned int *)mbrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800401 if (ret) {
402 dprintf(CRITICAL, "Failed to write mbr partition\n");
403 goto end;
404 }
405 dprintf(SPEW, "write of first MBR block ok\n");
406 /*
407 Loop through the MBR table to see if there is an EBR.
408 If found, then figure out where to write the first EBR
409 */
410 idx = TABLE_ENTRY_0;
411 for (i = 0; i < 4; i++) {
412 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
413 if (MBR_EBR_TYPE == dtype) {
414 dprintf(SPEW, "EBR found.\n");
415 break;
416 }
417 }
418 if (MBR_EBR_TYPE != dtype) {
419 dprintf(SPEW, "No EBR in this image\n");
420 goto end;
421 }
422 /* EBR exists. Write each EBR block to mmc */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700423 ebrImage = mbrImage + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800424 ebrSectorOffset =
425 GET_LWORD_FROM_BYTE(&mbrImage
426 [idx + i * TABLE_ENTRY_SIZE +
427 OFFSET_FIRST_SEC]);
428 dfirstsec = 0;
429 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
430 lastAddress = mbrImage + size;
431 while (ebrImage < lastAddress) {
432 dprintf(SPEW, "writing to 0x%X\n",
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700433 (ebrSectorOffset + dfirstsec) * block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800434 ret =
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700435 mmc_write((ebrSectorOffset + dfirstsec) * block_size,
436 block_size, (unsigned int *)ebrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800437 if (ret) {
438 dprintf(CRITICAL,
439 "Failed to write EBR block to sector 0x%X\n",
440 dfirstsec);
441 goto end;
442 }
443 dfirstsec =
444 GET_LWORD_FROM_BYTE(&ebrImage
445 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700446 ebrImage += block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800447 }
448 dprintf(INFO, "MBR written to mmc successfully\n");
449 end:
450 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700451}
452
453/* Write the MBR/EBR to the MMC. */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700454static unsigned int write_mbr(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700455{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800456 unsigned int ret;
Vijay Kumar Pendoti17c38532016-05-04 20:27:52 +0530457 uint64_t device_density;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700458
Ajay Dudanib01e5062011-12-03 23:23:42 -0800459 /* Verify that passed in block is a valid MBR */
460 ret = partition_verify_mbr_signature(size, mbrImage);
461 if (ret) {
462 goto end;
463 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700464
Vijay Kumar Pendoti17c38532016-05-04 20:27:52 +0530465 device_density = mmc_get_device_capacity();
466
467 /* Erasing the eMMC card before writing */
468 ret = mmc_erase_card(0x00000000, device_density);
469 if (ret) {
470 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
471 goto end;
472 }
473
Ajay Dudanib01e5062011-12-03 23:23:42 -0800474 /* Write the MBR/EBR to mmc */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700475 ret = write_mbr_in_blocks(size, mbrImage, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800476 if (ret) {
477 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
478 goto end;
479 }
480 /* Re-read the MBR partition into mbr table */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700481 ret = mmc_boot_read_mbr(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800482 if (ret) {
483 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
484 goto end;
485 }
486 partition_dump();
487 end:
488 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700489}
490
491/*
492 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
493*/
494int reflect(int data, int len)
495{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800496 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700497
Ajay Dudanib01e5062011-12-03 23:23:42 -0800498 for (int i = 0; i < len; i++) {
499 if (data & 0x1) {
500 ref |= (1 << ((len - 1) - i));
501 }
502 data = (data >> 1);
503 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700504
Ajay Dudanib01e5062011-12-03 23:23:42 -0800505 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700506}
507
508/*
509* Function to calculate the CRC32
510*/
511unsigned int calculate_crc32(unsigned char *buffer, int len)
512{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800513 int byte_length = 8; /*length of unit (i.e. byte) */
514 int msb = 0;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700515 int polynomial = 0x04C11DB7; /* IEEE 32bit polynomial */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800516 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
517 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
518 int regs_msb = 0;
519 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700520
Ajay Dudanib01e5062011-12-03 23:23:42 -0800521 for (int i = 0; i < len; i++) {
522 int data_byte = buffer[i];
523 data_byte = reflect(data_byte, 8);
524 for (int j = 0; j < byte_length; j++) {
525 msb = data_byte >> (byte_length - 1); /* get MSB */
526 msb &= 1; /* ensure just 1 bit */
527 regs_msb = (regs >> 31) & 1; /* MSB of regs */
528 regs = regs << 1; /* shift regs for CRC-CCITT */
529 if (regs_msb ^ msb) { /* MSB is a 1 */
530 regs = regs ^ polynomial; /* XOR with generator poly */
531 }
532 regs = regs & regs_mask; /* Mask off excess upper bits */
533 data_byte <<= 1; /* get to next bit */
534 }
535 }
536 regs = regs & regs_mask;
537 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700538
Ajay Dudanib01e5062011-12-03 23:23:42 -0800539 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700540}
541
542/*
543 * Write the GPT Partition Entry Array to the MMC.
544 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800545static unsigned int
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700546write_gpt_partition_array(uint8_t *header,
547 uint32_t partition_array_start,
548 uint32_t array_size,
549 uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700550{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700551 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800552 unsigned long long partition_entry_lba;
553 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700554
Ajay Dudanib01e5062011-12-03 23:23:42 -0800555 partition_entry_lba =
556 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700557 partition_entry_array_start_location = partition_entry_lba * block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700558
Ajay Dudanib01e5062011-12-03 23:23:42 -0800559 ret = mmc_write(partition_entry_array_start_location, array_size,
560 (unsigned int *)partition_array_start);
561 if (ret) {
562 dprintf(CRITICAL,
563 "GPT: FAILED to write the partition entry array\n");
564 goto end;
565 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700566
Ajay Dudanib01e5062011-12-03 23:23:42 -0800567 end:
568 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700569}
570
Ajay Dudanib01e5062011-12-03 23:23:42 -0800571static void
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700572patch_gpt(uint8_t *gptImage, uint64_t density, uint32_t array_size,
573 uint32_t max_part_count, uint32_t part_entry_size, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700574{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800575 unsigned int partition_entry_array_start;
576 unsigned char *primary_gpt_header;
577 unsigned char *secondary_gpt_header;
578 unsigned int offset;
579 unsigned long long card_size_sec;
580 int total_part = 0;
581 unsigned int last_part_offset;
582 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700583
Ajay Dudanib01e5062011-12-03 23:23:42 -0800584 /* Get size of MMC */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700585 card_size_sec = (density) / block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800586 /* Working around cap at 4GB */
587 if (card_size_sec == 0) {
588 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
589 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700590
Ajay Dudanib01e5062011-12-03 23:23:42 -0800591 /* Patching primary header */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700592 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800593 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
594 ((long long)(card_size_sec - 1)));
595 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
596 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700597
Ajay Dudanib01e5062011-12-03 23:23:42 -0800598 /* Patching backup GPT */
599 offset = (2 * array_size);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700600 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800601 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
602 ((long long)(card_size_sec - 1)));
603 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
604 ((long long)(card_size_sec - 34)));
605 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
606 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700607
Ajay Dudanib01e5062011-12-03 23:23:42 -0800608 /* Find last partition */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700609 while (*(primary_gpt_header + block_size + total_part * ENTRY_SIZE) !=
Ajay Dudanib01e5062011-12-03 23:23:42 -0800610 0) {
611 total_part++;
612 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700613
Ajay Dudanib01e5062011-12-03 23:23:42 -0800614 /* Patching last partition */
615 last_part_offset =
616 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700617 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800618 (long long)(card_size_sec - 34));
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700619 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800620 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700621
Ajay Dudanib01e5062011-12-03 23:23:42 -0800622 /* Updating CRC of the Partition entry array in both headers */
vijay kumar4f4405f2014-08-08 11:49:53 +0530623 partition_entry_array_start = (unsigned int)primary_gpt_header + block_size;
624 crc_value = calculate_crc32((unsigned char *)partition_entry_array_start,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800625 max_part_count * part_entry_size);
626 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700627
vijay kumar4f4405f2014-08-08 11:49:53 +0530628 crc_value = calculate_crc32((unsigned char *)partition_entry_array_start + array_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800629 max_part_count * part_entry_size);
630 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700631
Ajay Dudanib01e5062011-12-03 23:23:42 -0800632 /* Clearing CRC fields to calculate */
633 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
634 crc_value = calculate_crc32(primary_gpt_header, 92);
635 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700636
Ajay Dudanib01e5062011-12-03 23:23:42 -0800637 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
638 crc_value = (calculate_crc32(secondary_gpt_header, 92));
639 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700640
641}
642
643/*
644 * Write the GPT to the MMC.
645 */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700646static unsigned int write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700647{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700648 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800649 unsigned int header_size;
650 unsigned long long first_usable_lba;
651 unsigned long long backup_header_lba;
652 unsigned int max_partition_count = 0;
653 unsigned int partition_entry_size;
654 unsigned int partition_entry_array_start;
655 unsigned char *primary_gpt_header;
656 unsigned char *secondary_gpt_header;
657 unsigned int offset;
658 unsigned int partition_entry_array_size;
659 unsigned long long primary_header_location; /* address on the emmc card */
660 unsigned long long secondary_header_location; /* address on the emmc card */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700661 uint64_t device_density;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700662
Ajay Dudanib01e5062011-12-03 23:23:42 -0800663 /* Verify that passed block has a valid GPT primary header */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700664 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800665 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
666 &partition_entry_size, &header_size,
667 &max_partition_count);
668 if (ret) {
669 dprintf(CRITICAL,
670 "GPT: Primary signature invalid cannot write GPT\n");
671 goto end;
672 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700673
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700674 /* Get the density of the mmc device */
675
676 device_density = mmc_get_device_capacity();
677
Ajay Dudanib01e5062011-12-03 23:23:42 -0800678 /* Verify that passed block has a valid backup GPT HEADER */
679 partition_entry_array_size = partition_entry_size * max_partition_count;
680 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
681 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
682 }
683 offset = (2 * partition_entry_array_size);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700684 secondary_gpt_header = offset + block_size + primary_gpt_header;
vijay kumar24c9ed12015-04-28 13:05:04 +0530685 parse_secondary_gpt = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800686 ret =
687 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
688 &partition_entry_size, &header_size,
689 &max_partition_count);
vijay kumar24c9ed12015-04-28 13:05:04 +0530690 parse_secondary_gpt = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800691 if (ret) {
692 dprintf(CRITICAL,
693 "GPT: Backup signature invalid cannot write GPT\n");
694 goto end;
695 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700696
Ajay Dudanib01e5062011-12-03 23:23:42 -0800697 /* Patching the primary and the backup header of the GPT table */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700698 patch_gpt(gptImage, device_density, partition_entry_array_size,
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700699 max_partition_count, partition_entry_size, block_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700700
Ajay Dudanib01e5062011-12-03 23:23:42 -0800701 /* Erasing the eMMC card before writing */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700702 ret = mmc_erase_card(0x00000000, device_density);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800703 if (ret) {
704 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
705 goto end;
706 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700707
Ajay Dudanib01e5062011-12-03 23:23:42 -0800708 /* Writing protective MBR */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700709 ret = mmc_write(0, block_size, (unsigned int *)gptImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800710 if (ret) {
711 dprintf(CRITICAL, "Failed to write Protective MBR\n");
712 goto end;
713 }
714 /* Writing the primary GPT header */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700715 primary_header_location = block_size;
716 ret = mmc_write(primary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800717 (unsigned int *)primary_gpt_header);
718 if (ret) {
719 dprintf(CRITICAL, "Failed to write GPT header\n");
720 goto end;
721 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700722
Ajay Dudanib01e5062011-12-03 23:23:42 -0800723 /* Writing the backup GPT header */
724 backup_header_lba = GET_LLWORD_FROM_BYTE
725 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700726 secondary_header_location = backup_header_lba * block_size;
727 ret = mmc_write(secondary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800728 (unsigned int *)secondary_gpt_header);
729 if (ret) {
730 dprintf(CRITICAL, "Failed to write GPT backup header\n");
731 goto end;
732 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700733
Ajay Dudanib01e5062011-12-03 23:23:42 -0800734 /* Writing the partition entries array for the primary header */
vijay kumar4f4405f2014-08-08 11:49:53 +0530735 partition_entry_array_start = (unsigned int)primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800736 ret = write_gpt_partition_array(primary_gpt_header,
737 partition_entry_array_start,
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700738 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800739 if (ret) {
740 dprintf(CRITICAL,
741 "GPT: Could not write GPT Partition entries array\n");
742 goto end;
743 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700744
Ajay Dudanib01e5062011-12-03 23:23:42 -0800745 /*Writing the partition entries array for the backup header */
vijay kumar4f4405f2014-08-08 11:49:53 +0530746 partition_entry_array_start = (unsigned int)primary_gpt_header + block_size +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800747 partition_entry_array_size;
748 ret = write_gpt_partition_array(secondary_gpt_header,
749 partition_entry_array_start,
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700750 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800751 if (ret) {
752 dprintf(CRITICAL,
753 "GPT: Could not write GPT Partition entries array\n");
754 goto end;
755 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700756
Ajay Dudanib01e5062011-12-03 23:23:42 -0800757 /* Re-read the GPT partition table */
758 dprintf(INFO, "Re-reading the GPT Partition Table\n");
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -0800759 partition_count = 0;
vijay kumar24c9ed12015-04-28 13:05:04 +0530760 flashing_gpt = 0;
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -0800761 mmc_read_partition_table(0);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800762 partition_dump();
763 dprintf(CRITICAL, "GPT: Partition Table written\n");
764 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700765
Ajay Dudanib01e5062011-12-03 23:23:42 -0800766 end:
767 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700768}
769
Ajay Dudanib01e5062011-12-03 23:23:42 -0800770unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700771{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700772 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800773 unsigned int partition_type;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700774 uint32_t block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700775
Ajay Dudanib01e5062011-12-03 23:23:42 -0800776 if (partition == 0) {
777 dprintf(CRITICAL, "NULL partition\n");
778 goto end;
779 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700780
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700781 block_size = mmc_get_device_blocksize();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800782 ret = partition_get_type(size, partition, &partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700783 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800784 goto end;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700785
Ajay Dudanib01e5062011-12-03 23:23:42 -0800786 switch (partition_type) {
787 case PARTITION_TYPE_MBR:
788 dprintf(INFO, "Writing MBR partition\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700789 ret = write_mbr(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800790 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700791
Ajay Dudanib01e5062011-12-03 23:23:42 -0800792 case PARTITION_TYPE_GPT:
793 dprintf(INFO, "Writing GPT partition\n");
vijay kumar24c9ed12015-04-28 13:05:04 +0530794 flashing_gpt = 1;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700795 ret = write_gpt(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800796 dprintf(CRITICAL, "Re-Flash all the partitions\n");
797 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700798
Ajay Dudanib01e5062011-12-03 23:23:42 -0800799 default:
800 dprintf(CRITICAL, "Invalid partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700801 ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800802 goto end;
803 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700804
Ajay Dudanib01e5062011-12-03 23:23:42 -0800805 end:
806 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700807}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800808
Kinson Chikf1a43512011-07-14 11:28:39 -0700809/*
810 * Fill name for android partition found.
811 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800812static void
813mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700814{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800815 switch (type) {
816 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
817 case MBR_MODEM_TYPE:
818 case MBR_MODEM_TYPE2:
819 /* if already assigned last name available then return */
820 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
821 return;
822 strlcpy((char *)partition_ent->name,
823 (const char *)vfat_partitions[vfat_count],
824 sizeof(partition_ent->name));
825 vfat_count++;
826 break;
827 case MBR_SBL1_TYPE:
828 memcpy(partition_ent->name, "sbl1", 4);
829 break;
830 case MBR_SBL2_TYPE:
831 memcpy(partition_ent->name, "sbl2", 4);
832 break;
833 case MBR_SBL3_TYPE:
834 memcpy(partition_ent->name, "sbl3", 4);
835 break;
836 case MBR_RPM_TYPE:
837 memcpy(partition_ent->name, "rpm", 3);
838 break;
839 case MBR_TZ_TYPE:
840 memcpy(partition_ent->name, "tz", 2);
841 break;
842 case MBR_ABOOT_TYPE:
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530843#if PLATFORM_MSM7X27A
844 memcpy(partition_ent->name, "FOTA", 4);
845#else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800846 memcpy(partition_ent->name, "aboot", 5);
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530847#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -0800848 break;
849 case MBR_BOOT_TYPE:
850 memcpy(partition_ent->name, "boot", 4);
851 break;
852 case MBR_MODEM_ST1_TYPE:
853 memcpy(partition_ent->name, "modem_st1", 9);
854 break;
855 case MBR_MODEM_ST2_TYPE:
856 memcpy(partition_ent->name, "modem_st2", 9);
857 break;
858 case MBR_EFS2_TYPE:
859 memcpy(partition_ent->name, "efs2", 4);
860 break;
861 case MBR_USERDATA_TYPE:
862 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
863 return;
864 strlcpy((char *)partition_ent->name,
865 (const char *)ext3_partitions[ext3_count],
866 sizeof(partition_ent->name));
867 ext3_count++;
868 break;
869 case MBR_RECOVERY_TYPE:
870 memcpy(partition_ent->name, "recovery", 8);
871 break;
872 case MBR_MISC_TYPE:
873 memcpy(partition_ent->name, "misc", 4);
874 break;
Neeti Desai2d6b0e42012-03-23 15:48:57 -0700875 case MBR_SSD_TYPE:
876 memcpy(partition_ent->name, "ssd", 3);
877 break;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800878 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700879}
880
881/*
882 * Find index of parition in array of partition entries
883 */
Pavel Nedev285ad922013-04-26 10:39:19 +0300884int partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700885{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800886 unsigned int input_string_length = strlen(name);
887 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700888
neetid6c38de12011-12-02 12:04:50 -0800889 if( partition_count >= NUM_PARTITIONS)
890 {
891 return INVALID_PTN;
892 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800893 for (n = 0; n < partition_count; n++) {
Channagoud Kadabif8c5bf72015-02-26 11:33:52 -0800894 if ((input_string_length == strlen((const char *)&partition_entries[n].name))
895 && !memcmp(name, &partition_entries[n].name, input_string_length)) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800896 return n;
897 }
898 }
899 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700900}
901
902/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800903unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700904{
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700905 uint32_t block_size;
906
907 block_size = mmc_get_device_blocksize();
908
Ajay Dudanib01e5062011-12-03 23:23:42 -0800909 if (index == INVALID_PTN)
910 return 0;
911 else {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700912 return partition_entries[index].size * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800913 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700914}
915
916/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800917unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700918{
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700919 uint32_t block_size;
920
921 block_size = mmc_get_device_blocksize();
922
Ajay Dudanib01e5062011-12-03 23:23:42 -0800923 if (index == INVALID_PTN)
924 return 0;
925 else {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700926 return partition_entries[index].first_lba * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800927 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700928}
929
Sundarajan Srinivasan9ec69632014-04-10 13:33:10 -0700930struct partition_info partition_get_info(const char *name)
931{
932 struct partition_info info = {0};
933
934 int index = INVALID_PTN;
935
936 if(!name)
937 {
938 dprintf(CRITICAL, "Invalid partition name passed\n");
939 goto out;
940 }
941
942 index = partition_get_index(name);
943
944 if (index != INVALID_PTN)
945 {
946 info.offset = partition_get_offset(index);
947 info.size = partition_get_size(index);
948 }
949 else
950 {
951 dprintf(CRITICAL, "Error unable to find partition : [%s]\n", name);
952 }
953out:
954 return info;
955}
956
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -0800957uint8_t partition_get_lun(int index)
958{
959 return partition_entries[index].lun;
960}
961
Kinson Chikf1a43512011-07-14 11:28:39 -0700962/* Debug: Print all parsed partitions */
963void partition_dump()
964{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800965 unsigned i = 0;
966 for (i = 0; i < partition_count; i++) {
967 dprintf(SPEW,
968 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
969 i, partition_entries[i].name, partition_entries[i].size,
970 partition_entries[i].dtype,
971 partition_entries[i].first_lba,
972 partition_entries[i].last_lba);
973 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700974}
975
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700976static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800977partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700978{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800979 /* Avoid checking past end of buffer */
980 if ((TABLE_SIGNATURE + 1) > size) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700981 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800982 }
983 /* Check to see if signature exists */
984 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
985 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
986 dprintf(CRITICAL, "MBR signature does not match.\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700987 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800988 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700989 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700990}
991
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700992static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800993mbr_partition_get_type(unsigned size, unsigned char *partition,
994 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700995{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800996 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700997
Channagoud Kadabi98b11072015-03-12 15:14:22 -0700998 if (size < (type_offset + sizeof (*partition_type))) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800999 goto end;
1000 }
Kinson Chikf1a43512011-07-14 11:28:39 -07001001
Ajay Dudanib01e5062011-12-03 23:23:42 -08001002 *partition_type = partition[type_offset];
1003 end:
Channagoud Kadabi0e332852013-04-19 12:55:53 -07001004 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -07001005}
1006
Channagoud Kadabi0e332852013-04-19 12:55:53 -07001007static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -08001008partition_get_type(unsigned size, unsigned char *partition,
1009 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -07001010{
Channagoud Kadabi0e332852013-04-19 12:55:53 -07001011 unsigned int ret = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -07001012
Ajay Dudanib01e5062011-12-03 23:23:42 -08001013 /*
1014 * If the block contains the MBR signature, then it's likely either
1015 * MBR or MBR with protective type (GPT). If the MBR signature is
1016 * not there, then it could be the GPT backup.
1017 */
Kinson Chikf1a43512011-07-14 11:28:39 -07001018
Ajay Dudanib01e5062011-12-03 23:23:42 -08001019 /* First check the MBR signature */
1020 ret = partition_verify_mbr_signature(size, partition);
Channagoud Kadabi0e332852013-04-19 12:55:53 -07001021 if (!ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -08001022 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -07001023
Ajay Dudanib01e5062011-12-03 23:23:42 -08001024 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
1025 ret =
1026 mbr_partition_get_type(size, partition,
1027 &mbr_partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -07001028 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -08001029 dprintf(CRITICAL, "Cannot get TYPE of partition");
1030 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
1031 *partition_type = PARTITION_TYPE_GPT;
1032 } else {
1033 *partition_type = PARTITION_TYPE_MBR;
1034 }
1035 } else {
1036 /*
1037 * This could be the GPT backup. Make that assumption for now.
1038 * Anybody who treats the block as GPT backup should check the
1039 * signature.
1040 */
1041 *partition_type = PARTITION_TYPE_GPT_BACKUP;
1042 }
1043 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -07001044}
Kinson Chik4d7444f2011-09-13 15:48:51 -07001045
1046/*
1047 * Parse the gpt header and get the required header fields
1048 * Return 0 on valid signature
1049 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -07001050static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -08001051partition_parse_gpt_header(unsigned char *buffer,
1052 unsigned long long *first_usable_lba,
1053 unsigned int *partition_entry_size,
1054 unsigned int *header_size,
1055 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -07001056{
vijay kumar24c9ed12015-04-28 13:05:04 +05301057 uint32_t crc_val_org = 0;
1058 uint32_t crc_val = 0;
1059 uint32_t ret = 0;
1060 uint32_t partitions_for_block = 0;
1061 uint32_t blocks_to_read = 0;
1062 unsigned char *new_buffer = NULL;
1063 unsigned long long last_usable_lba = 0;
1064 unsigned long long partition_0 = 0;
1065 unsigned long long current_lba = 0;
1066 uint32_t block_size = mmc_get_device_blocksize();
1067 /* Get the density of the mmc device */
1068 uint64_t device_density = mmc_get_device_capacity();
1069
Ajay Dudanib01e5062011-12-03 23:23:42 -08001070 /* Check GPT Signature */
1071 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
1072 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
1073 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001074
Ajay Dudanib01e5062011-12-03 23:23:42 -08001075 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
vijay kumar24c9ed12015-04-28 13:05:04 +05301076 /*check for header size too small*/
1077 if (*header_size < GPT_HEADER_SIZE) {
1078 dprintf(CRITICAL,"GPT Header size is too small\n");
1079 return 1;
1080 }
1081 /*check for header size too large*/
1082 if (*header_size > block_size) {
1083 dprintf(CRITICAL,"GPT Header size is too large\n");
1084 return 1;
1085 }
1086
1087 crc_val_org = GET_LWORD_FROM_BYTE(&buffer[HEADER_CRC_OFFSET]);
1088 /*Write CRC to 0 before we calculate the crc of the GPT header*/
1089 crc_val = 0;
1090 PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);
1091
1092 crc_val = crc32(~0L,buffer, *header_size) ^ (~0L);
1093 if (crc_val != crc_val_org) {
1094 dprintf(CRITICAL,"Header crc mismatch crc_val = %u with crc_val_org = %u\n", crc_val,crc_val_org);
1095 return 1;
1096 }
1097 else
1098 PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);
1099
1100 current_lba =
1101 GET_LLWORD_FROM_BYTE(&buffer[PRIMARY_HEADER_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -08001102 *first_usable_lba =
1103 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
1104 *max_partition_count =
1105 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
1106 *partition_entry_size =
1107 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
vijay kumar24c9ed12015-04-28 13:05:04 +05301108 last_usable_lba =
1109 GET_LLWORD_FROM_BYTE(&buffer[LAST_USABLE_LBA_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -07001110
vijay kumar24c9ed12015-04-28 13:05:04 +05301111 /*current lba and GPT lba should be same*/
1112 if (!parse_secondary_gpt) {
1113 if (current_lba != GPT_LBA) {
1114 dprintf(CRITICAL,"GPT first usable LBA mismatch\n");
1115 return 1;
1116 }
1117 }
1118 /*check for first lba should be with in the valid range*/
1119 if (*first_usable_lba > (device_density/block_size)) {
1120 dprintf(CRITICAL,"Invalid first_usable_lba\n");
1121 return 1;
1122 }
1123 /*check for last lba should be with in the valid range*/
1124 if (last_usable_lba > (device_density/block_size)) {
1125 dprintf(CRITICAL,"Invalid last_usable_lba\n");
1126 return 1;
1127 }
1128 /*check for partition entry size*/
1129 if (*partition_entry_size != PARTITION_ENTRY_SIZE) {
1130 dprintf(CRITICAL,"Invalid parition entry size\n");
1131 return 1;
1132 }
1133
1134 if ((*max_partition_count) > (MIN_PARTITION_ARRAY_SIZE /(*partition_entry_size))) {
1135 dprintf(CRITICAL, "Invalid maximum partition count\n");
1136 return 1;
1137 }
1138
1139 partitions_for_block = block_size / (*partition_entry_size);
1140
1141 blocks_to_read = (*max_partition_count)/ partitions_for_block;
1142 if ((*max_partition_count) % partitions_for_block) {
1143 blocks_to_read += 1;
1144 }
1145
1146 new_buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP((blocks_to_read * block_size),CACHE_LINE));
1147
1148 if (!new_buffer)
1149 {
1150 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
1151 return 1;
1152 }
1153
1154 if (!flashing_gpt) {
1155 partition_0 = GET_LLWORD_FROM_BYTE(&buffer[PARTITION_ENTRIES_OFFSET]);
1156 /*start LBA should always be 2 in primary GPT*/
1157 if(partition_0 != 0x2) {
1158 dprintf(CRITICAL, "Starting LBA mismatch\n");
1159 goto fail;
1160
1161 }
1162 /*read the partition entries to new_buffer*/
1163 ret = mmc_read((partition_0) * (block_size), (unsigned int *)new_buffer, (blocks_to_read * block_size));
1164 if (ret)
1165 {
1166 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
1167 goto fail;
1168 }
1169 crc_val_org = GET_LWORD_FROM_BYTE(&buffer[PARTITION_CRC_OFFSET]);
1170
1171 crc_val = crc32(~0L,new_buffer, ((*max_partition_count) * (*partition_entry_size))) ^ (~0L);
1172 if (crc_val != crc_val_org) {
1173 dprintf(CRITICAL,"Partition entires crc mismatch crc_val= %u with crc_val_org= %u\n",crc_val,crc_val_org);
1174 ret = 1;
1175 }
1176 }
1177fail:
1178 free(new_buffer);
1179 return ret;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001180}
Pavel Nedevb5ba62d2013-07-22 11:57:41 +03001181
1182bool partition_gpt_exists()
1183{
1184 return (gpt_partitions_exist != 0);
1185}
Channagoud Kadabifaf20f62014-10-21 22:22:37 -07001186
1187int partition_read_only(int index)
1188{
1189 return partition_entries[index].attribute_flag >> PART_ATT_READONLY_OFFSET;
1190}