blob: e7fb0e5bee6a4ae58bbb6713d778d215b100a829 [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
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -080040__WEAK void mmc_set_lun(uint8_t lun)
41{
42}
43
44__WEAK uint8_t mmc_get_lun(void)
45{
46 return 0;
47}
48
49__WEAK void mmc_read_partition_table(uint8_t arg)
50{
51 if(partition_read_table())
52 {
53 dprintf(CRITICAL, "Error reading the partition table info\n");
54 ASSERT(0);
55 }
56}
57
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070058static uint32_t mmc_boot_read_gpt(uint32_t block_size);
59static uint32_t mmc_boot_read_mbr(uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070060static void mbr_fill_name(struct partition_entry *partition_ent,
61 uint32_t type);
62static uint32_t partition_verify_mbr_signature(uint32_t size,
63 uint8_t *buffer);
64static uint32_t mbr_partition_get_type(uint32_t size, uint8_t *partition,
65 uint32_t *partition_type);
66
67static uint32_t partition_get_type(uint32_t size, uint8_t *partition,
68 uint32_t *partition_type);
69static uint32_t partition_parse_gpt_header(uint8_t *buffer,
70 uint64_t *first_usable_lba,
71 uint32_t *partition_entry_size,
72 uint32_t *header_size,
73 uint32_t *max_partition_count);
74
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070075static uint32_t write_mbr(uint32_t, uint8_t *mbrImage, uint32_t block_size);
76static uint32_t write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070077
Ajay Dudanib01e5062011-12-03 23:23:42 -080078char *ext3_partitions[] =
79 { "system", "userdata", "persist", "cache", "tombstones" };
80char *vfat_partitions[] = { "modem", "mdm", "NONE" };
81
Kinson Chikf1a43512011-07-14 11:28:39 -070082unsigned int ext3_count = 0;
83unsigned int vfat_count = 0;
84
Channagoud Kadabie9b94022013-11-12 13:49:41 -080085struct partition_entry *partition_entries;
Pavel Nedevb5ba62d2013-07-22 11:57:41 +030086static unsigned gpt_partitions_exist = 0;
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -080087static unsigned partition_count;
Kinson Chikf1a43512011-07-14 11:28:39 -070088
Channagoud Kadabi0e332852013-04-19 12:55:53 -070089unsigned int partition_read_table()
Kinson Chikf1a43512011-07-14 11:28:39 -070090{
Ajay Dudanib01e5062011-12-03 23:23:42 -080091 unsigned int ret;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070092 uint32_t block_size;
93
94 block_size = mmc_get_device_blocksize();
Kinson Chikf1a43512011-07-14 11:28:39 -070095
Channagoud Kadabie9b94022013-11-12 13:49:41 -080096 /* Allocate partition entries array */
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -080097 if(!partition_entries)
98 {
99 partition_entries = (struct partition_entry *) calloc(NUM_PARTITIONS, sizeof(struct partition_entry));
100 ASSERT(partition_entries);
101 }
Channagoud Kadabie9b94022013-11-12 13:49:41 -0800102
Ajay Dudanib01e5062011-12-03 23:23:42 -0800103 /* Read MBR of the card */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700104 ret = mmc_boot_read_mbr(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700105 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800106 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700107 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800108 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700109
Ajay Dudanib01e5062011-12-03 23:23:42 -0800110 /* Read GPT of the card if exist */
111 if (gpt_partitions_exist) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700112 ret = mmc_boot_read_gpt(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700113 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800114 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700115 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800116 }
117 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700118 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700119}
120
121/*
122 * Read MBR from MMC card and fill partition table.
123 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700124static unsigned int mmc_boot_read_mbr(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700125{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700126 uint8_t *buffer = NULL;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800127 unsigned int dtype;
128 unsigned int dfirstsec;
129 unsigned int EBR_first_sec;
130 unsigned int EBR_current_sec;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700131 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800132 int idx, i;
Kinson Chikf1a43512011-07-14 11:28:39 -0700133
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700134 buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
135
136 if (!buffer)
137 {
138 dprintf(CRITICAL, "Error allocating memory while reading partition table\n");
139 ret = -1;
140 goto end;
141 }
142
Ajay Dudanib01e5062011-12-03 23:23:42 -0800143 /* Print out the MBR first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700144 ret = mmc_read(0, (unsigned int *)buffer, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800145 if (ret) {
146 dprintf(CRITICAL, "Could not read partition from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700147 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800148 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700149
Ajay Dudanib01e5062011-12-03 23:23:42 -0800150 /* Check to see if signature exists */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700151 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800152 if (ret) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700153 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800154 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700155
Ajay Dudanib01e5062011-12-03 23:23:42 -0800156 /*
157 * Process each of the four partitions in the MBR by reading the table
158 * information into our mbr table.
159 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800160 idx = TABLE_ENTRY_0;
161 for (i = 0; i < 4; i++) {
162 /* Type 0xEE indicates end of MBR and GPT partitions exist */
163 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
164 if (dtype == MBR_PROTECTED_TYPE) {
165 gpt_partitions_exist = 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700166 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800167 }
168 partition_entries[partition_count].dtype = dtype;
169 partition_entries[partition_count].attribute_flag =
170 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
171 partition_entries[partition_count].first_lba =
172 GET_LWORD_FROM_BYTE(&buffer[idx +
173 i * TABLE_ENTRY_SIZE +
174 OFFSET_FIRST_SEC]);
175 partition_entries[partition_count].size =
176 GET_LWORD_FROM_BYTE(&buffer[idx +
177 i * TABLE_ENTRY_SIZE +
178 OFFSET_SIZE]);
179 dfirstsec = partition_entries[partition_count].first_lba;
180 mbr_fill_name(&partition_entries[partition_count],
181 partition_entries[partition_count].dtype);
182 partition_count++;
183 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700184 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800185 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700186
Ajay Dudanib01e5062011-12-03 23:23:42 -0800187 /* See if the last partition is EBR, if not, parsing is done */
188 if (dtype != MBR_EBR_TYPE) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700189 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800190 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700191
Ajay Dudanib01e5062011-12-03 23:23:42 -0800192 EBR_first_sec = dfirstsec;
193 EBR_current_sec = dfirstsec;
Kinson Chikf1a43512011-07-14 11:28:39 -0700194
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700195 ret = mmc_read((EBR_first_sec * block_size), (unsigned int *)buffer, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700196 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700197 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700198
Ajay Dudanib01e5062011-12-03 23:23:42 -0800199 /* Loop to parse the EBR */
200 for (i = 0;; i++) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700201 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800202 if (ret) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700203 ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800204 break;
205 }
206 partition_entries[partition_count].attribute_flag =
207 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
208 partition_entries[partition_count].dtype =
209 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
210 partition_entries[partition_count].first_lba =
211 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
212 OFFSET_FIRST_SEC]) +
213 EBR_current_sec;
214 partition_entries[partition_count].size =
215 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
216 mbr_fill_name(&(partition_entries[partition_count]),
217 partition_entries[partition_count].dtype);
218 partition_count++;
219 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700220 goto end;
Kinson Chikf1a43512011-07-14 11:28:39 -0700221
Ajay Dudanib01e5062011-12-03 23:23:42 -0800222 dfirstsec =
223 GET_LWORD_FROM_BYTE(&buffer
224 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
225 if (dfirstsec == 0) {
226 /* Getting to the end of the EBR tables */
227 break;
228 }
229 /* More EBR to follow - read in the next EBR sector */
230 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
231 + dfirstsec);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700232 ret = mmc_read(((EBR_first_sec + dfirstsec) * block_size),(unsigned int *)buffer,
233 block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700234 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700235 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700236
Ajay Dudanib01e5062011-12-03 23:23:42 -0800237 EBR_current_sec = EBR_first_sec + dfirstsec;
238 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700239end:
240 if (buffer)
241 free(buffer);
242
Ajay Dudanib01e5062011-12-03 23:23:42 -0800243 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700244}
Kinson Chik66552a82011-03-29 15:59:06 -0700245
246/*
247 * Read GPT from MMC and fill partition table
248 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700249static unsigned int mmc_boot_read_gpt(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700250{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700251 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800252 unsigned int header_size;
253 unsigned long long first_usable_lba;
254 unsigned long long backup_header_lba;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700255 unsigned long long card_size_sec;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800256 unsigned int max_partition_count = 0;
257 unsigned int partition_entry_size;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700258 unsigned int i = 0; /* Counter for each block */
259 unsigned int j = 0; /* Counter for each entry in a block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800260 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
261 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
262 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700263 unsigned long long partition_0;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700264 uint64_t device_density;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700265 uint8_t *data = NULL;
266 uint32_t part_entry_cnt = block_size / ENTRY_SIZE;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700267
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700268 /* Get the density of the mmc device */
269
270 device_density = mmc_get_device_capacity();
271
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700272 data = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
273 if (!data)
274 {
275 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
276 ret = -1;
277 goto end;
278 }
279
Ajay Dudanib01e5062011-12-03 23:23:42 -0800280 /* Print out the GPT first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700281 ret = mmc_read(block_size, (unsigned int *)data, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700282 if (ret)
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700283 {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800284 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700285 goto end;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700286 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800287 ret = partition_parse_gpt_header(data, &first_usable_lba,
288 &partition_entry_size, &header_size,
289 &max_partition_count);
290 if (ret) {
291 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700292
Ajay Dudanib01e5062011-12-03 23:23:42 -0800293 /* Check the backup gpt */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700294
295 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700296 card_size_sec = (device_density) / block_size;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700297 ASSERT (card_size_sec > 0);
298
299 backup_header_lba = card_size_sec - 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700300 ret = mmc_read((backup_header_lba * block_size), (unsigned int *)data,
301 block_size);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700302
Ajay Dudanib01e5062011-12-03 23:23:42 -0800303 if (ret) {
304 dprintf(CRITICAL,
305 "GPT: Could not read backup gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700306 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800307 }
vijay kumarfe623342015-07-22 12:42:06 +0530308 parse_secondary_gpt = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800309 ret = partition_parse_gpt_header(data, &first_usable_lba,
310 &partition_entry_size,
311 &header_size,
312 &max_partition_count);
313 if (ret) {
314 dprintf(CRITICAL,
315 "GPT: Primary and backup signatures invalid\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700316 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800317 }
vijay kumarfe623342015-07-22 12:42:06 +0530318 parse_secondary_gpt = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800319 }
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700320 partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800321 /* Read GPT Entries */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700322 for (i = 0; i < (ROUNDUP(max_partition_count, part_entry_cnt)) / part_entry_cnt; i++) {
neetid6c38de12011-12-02 12:04:50 -0800323 ASSERT(partition_count < NUM_PARTITIONS);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700324 ret = mmc_read((partition_0 * block_size) + (i * block_size),
325 (uint32_t *) data, block_size);
Kinson Chik66552a82011-03-29 15:59:06 -0700326
Ajay Dudanib01e5062011-12-03 23:23:42 -0800327 if (ret) {
328 dprintf(CRITICAL,
329 "GPT: mmc read card failed reading partition entries.\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700330 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800331 }
Kinson Chik66552a82011-03-29 15:59:06 -0700332
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700333 for (j = 0; j < part_entry_cnt; j++) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800334 memcpy(&(partition_entries[partition_count].type_guid),
335 &data[(j * partition_entry_size)],
336 PARTITION_TYPE_GUID_SIZE);
337 if (partition_entries[partition_count].type_guid[0] ==
338 0x00
339 && partition_entries[partition_count].
340 type_guid[1] == 0x00) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700341 i = ROUNDUP(max_partition_count, part_entry_cnt);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800342 break;
343 }
344 memcpy(&
345 (partition_entries[partition_count].
346 unique_partition_guid),
347 &data[(j * partition_entry_size) +
348 UNIQUE_GUID_OFFSET],
349 UNIQUE_PARTITION_GUID_SIZE);
350 partition_entries[partition_count].first_lba =
351 GET_LLWORD_FROM_BYTE(&data
352 [(j * partition_entry_size) +
353 FIRST_LBA_OFFSET]);
354 partition_entries[partition_count].last_lba =
355 GET_LLWORD_FROM_BYTE(&data
356 [(j * partition_entry_size) +
357 LAST_LBA_OFFSET]);
358 partition_entries[partition_count].size =
359 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700360 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800361 partition_entries[partition_count].attribute_flag =
362 GET_LLWORD_FROM_BYTE(&data
363 [(j * partition_entry_size) +
364 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700365
Ajay Dudanib01e5062011-12-03 23:23:42 -0800366 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
367 memcpy(UTF16_name, &data[(j * partition_entry_size) +
368 PARTITION_NAME_OFFSET],
369 MAX_GPT_NAME_SIZE);
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -0800370 partition_entries[partition_count].lun = mmc_get_lun();
371
Ajay Dudanib01e5062011-12-03 23:23:42 -0800372 /*
373 * Currently partition names in *.xml are UTF-8 and lowercase
374 * Only supporting english for now so removing 2nd byte of UTF-16
375 */
376 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
377 partition_entries[partition_count].name[n] =
378 UTF16_name[n * 2];
379 }
380 partition_count++;
381 }
382 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700383end:
384 if (data)
385 free(data);
386
Ajay Dudanib01e5062011-12-03 23:23:42 -0800387 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700388}
389
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700390static unsigned int write_mbr_in_blocks(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700391{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800392 unsigned int dtype;
393 unsigned int dfirstsec;
394 unsigned int ebrSectorOffset;
395 unsigned char *ebrImage;
396 unsigned char *lastAddress;
397 int idx, i;
398 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700399
Ajay Dudanib01e5062011-12-03 23:23:42 -0800400 /* Write the first block */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700401 ret = mmc_write(0, block_size, (unsigned int *)mbrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800402 if (ret) {
403 dprintf(CRITICAL, "Failed to write mbr partition\n");
404 goto end;
405 }
406 dprintf(SPEW, "write of first MBR block ok\n");
407 /*
408 Loop through the MBR table to see if there is an EBR.
409 If found, then figure out where to write the first EBR
410 */
411 idx = TABLE_ENTRY_0;
412 for (i = 0; i < 4; i++) {
413 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
414 if (MBR_EBR_TYPE == dtype) {
415 dprintf(SPEW, "EBR found.\n");
416 break;
417 }
418 }
419 if (MBR_EBR_TYPE != dtype) {
420 dprintf(SPEW, "No EBR in this image\n");
421 goto end;
422 }
423 /* EBR exists. Write each EBR block to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700424 ebrImage = mbrImage + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800425 ebrSectorOffset =
426 GET_LWORD_FROM_BYTE(&mbrImage
427 [idx + i * TABLE_ENTRY_SIZE +
428 OFFSET_FIRST_SEC]);
429 dfirstsec = 0;
430 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
431 lastAddress = mbrImage + size;
432 while (ebrImage < lastAddress) {
433 dprintf(SPEW, "writing to 0x%X\n",
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700434 (ebrSectorOffset + dfirstsec) * block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800435 ret =
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700436 mmc_write((ebrSectorOffset + dfirstsec) * block_size,
437 block_size, (unsigned int *)ebrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800438 if (ret) {
439 dprintf(CRITICAL,
440 "Failed to write EBR block to sector 0x%X\n",
441 dfirstsec);
442 goto end;
443 }
444 dfirstsec =
445 GET_LWORD_FROM_BYTE(&ebrImage
446 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700447 ebrImage += block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800448 }
449 dprintf(INFO, "MBR written to mmc successfully\n");
450 end:
451 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700452}
453
454/* Write the MBR/EBR to the MMC. */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700455static unsigned int write_mbr(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700456{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800457 unsigned int ret;
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
Ajay Dudanib01e5062011-12-03 23:23:42 -0800465 /* Write the MBR/EBR to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700466 ret = write_mbr_in_blocks(size, mbrImage, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800467 if (ret) {
468 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
469 goto end;
470 }
471 /* Re-read the MBR partition into mbr table */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700472 ret = mmc_boot_read_mbr(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800473 if (ret) {
474 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
475 goto end;
476 }
477 partition_dump();
478 end:
479 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700480}
481
482/*
483 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
484*/
485int reflect(int data, int len)
486{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800487 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700488
Ajay Dudanib01e5062011-12-03 23:23:42 -0800489 for (int i = 0; i < len; i++) {
490 if (data & 0x1) {
491 ref |= (1 << ((len - 1) - i));
492 }
493 data = (data >> 1);
494 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700495
Ajay Dudanib01e5062011-12-03 23:23:42 -0800496 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700497}
498
499/*
500* Function to calculate the CRC32
501*/
502unsigned int calculate_crc32(unsigned char *buffer, int len)
503{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800504 int byte_length = 8; /*length of unit (i.e. byte) */
505 int msb = 0;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700506 int polynomial = 0x04C11DB7; /* IEEE 32bit polynomial */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800507 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
508 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
509 int regs_msb = 0;
510 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700511
Ajay Dudanib01e5062011-12-03 23:23:42 -0800512 for (int i = 0; i < len; i++) {
513 int data_byte = buffer[i];
514 data_byte = reflect(data_byte, 8);
515 for (int j = 0; j < byte_length; j++) {
516 msb = data_byte >> (byte_length - 1); /* get MSB */
517 msb &= 1; /* ensure just 1 bit */
518 regs_msb = (regs >> 31) & 1; /* MSB of regs */
519 regs = regs << 1; /* shift regs for CRC-CCITT */
520 if (regs_msb ^ msb) { /* MSB is a 1 */
521 regs = regs ^ polynomial; /* XOR with generator poly */
522 }
523 regs = regs & regs_mask; /* Mask off excess upper bits */
524 data_byte <<= 1; /* get to next bit */
525 }
526 }
527 regs = regs & regs_mask;
528 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700529
Ajay Dudanib01e5062011-12-03 23:23:42 -0800530 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700531}
532
533/*
534 * Write the GPT Partition Entry Array to the MMC.
535 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800536static unsigned int
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700537write_gpt_partition_array(uint8_t *header,
538 uint32_t partition_array_start,
539 uint32_t array_size,
540 uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700541{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700542 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800543 unsigned long long partition_entry_lba;
544 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700545
Ajay Dudanib01e5062011-12-03 23:23:42 -0800546 partition_entry_lba =
547 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700548 partition_entry_array_start_location = partition_entry_lba * block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700549
Ajay Dudanib01e5062011-12-03 23:23:42 -0800550 ret = mmc_write(partition_entry_array_start_location, array_size,
551 (unsigned int *)partition_array_start);
552 if (ret) {
553 dprintf(CRITICAL,
554 "GPT: FAILED to write the partition entry array\n");
555 goto end;
556 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700557
Ajay Dudanib01e5062011-12-03 23:23:42 -0800558 end:
559 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700560}
561
Ajay Dudanib01e5062011-12-03 23:23:42 -0800562static void
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700563patch_gpt(uint8_t *gptImage, uint64_t density, uint32_t array_size,
564 uint32_t max_part_count, uint32_t part_entry_size, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700565{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800566 unsigned int partition_entry_array_start;
567 unsigned char *primary_gpt_header;
568 unsigned char *secondary_gpt_header;
569 unsigned int offset;
570 unsigned long long card_size_sec;
571 int total_part = 0;
572 unsigned int last_part_offset;
573 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700574
Ajay Dudanib01e5062011-12-03 23:23:42 -0800575 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700576 card_size_sec = (density) / block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800577 /* Working around cap at 4GB */
578 if (card_size_sec == 0) {
579 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
580 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700581
Ajay Dudanib01e5062011-12-03 23:23:42 -0800582 /* Patching primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700583 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800584 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
585 ((long long)(card_size_sec - 1)));
586 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
587 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700588
Ajay Dudanib01e5062011-12-03 23:23:42 -0800589 /* Patching backup GPT */
590 offset = (2 * array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700591 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800592 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
593 ((long long)(card_size_sec - 1)));
594 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
595 ((long long)(card_size_sec - 34)));
596 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
597 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700598
Ajay Dudanib01e5062011-12-03 23:23:42 -0800599 /* Find last partition */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700600 while (*(primary_gpt_header + block_size + total_part * ENTRY_SIZE) !=
Ajay Dudanib01e5062011-12-03 23:23:42 -0800601 0) {
602 total_part++;
603 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700604
Ajay Dudanib01e5062011-12-03 23:23:42 -0800605 /* Patching last partition */
606 last_part_offset =
607 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700608 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800609 (long long)(card_size_sec - 34));
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700610 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800611 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700612
Ajay Dudanib01e5062011-12-03 23:23:42 -0800613 /* Updating CRC of the Partition entry array in both headers */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700614 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800615 crc_value = calculate_crc32(partition_entry_array_start,
616 max_part_count * part_entry_size);
617 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700618
Ajay Dudanib01e5062011-12-03 23:23:42 -0800619 crc_value = calculate_crc32(partition_entry_array_start + array_size,
620 max_part_count * part_entry_size);
621 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700622
Ajay Dudanib01e5062011-12-03 23:23:42 -0800623 /* Clearing CRC fields to calculate */
624 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
625 crc_value = calculate_crc32(primary_gpt_header, 92);
626 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700627
Ajay Dudanib01e5062011-12-03 23:23:42 -0800628 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
629 crc_value = (calculate_crc32(secondary_gpt_header, 92));
630 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700631
632}
633
634/*
635 * Write the GPT to the MMC.
636 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700637static unsigned int write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700638{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700639 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800640 unsigned int header_size;
641 unsigned long long first_usable_lba;
642 unsigned long long backup_header_lba;
643 unsigned int max_partition_count = 0;
644 unsigned int partition_entry_size;
645 unsigned int partition_entry_array_start;
646 unsigned char *primary_gpt_header;
647 unsigned char *secondary_gpt_header;
648 unsigned int offset;
649 unsigned int partition_entry_array_size;
650 unsigned long long primary_header_location; /* address on the emmc card */
651 unsigned long long secondary_header_location; /* address on the emmc card */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700652 uint64_t device_density;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700653
Ajay Dudanib01e5062011-12-03 23:23:42 -0800654 /* Verify that passed block has a valid GPT primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700655 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800656 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
657 &partition_entry_size, &header_size,
658 &max_partition_count);
659 if (ret) {
660 dprintf(CRITICAL,
661 "GPT: Primary signature invalid cannot write GPT\n");
662 goto end;
663 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700664
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700665 /* Get the density of the mmc device */
666
667 device_density = mmc_get_device_capacity();
668
Ajay Dudanib01e5062011-12-03 23:23:42 -0800669 /* Verify that passed block has a valid backup GPT HEADER */
670 partition_entry_array_size = partition_entry_size * max_partition_count;
671 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
672 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
673 }
674 offset = (2 * partition_entry_array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700675 secondary_gpt_header = offset + block_size + primary_gpt_header;
vijay kumarc8c60a02015-04-28 13:05:04 +0530676 parse_secondary_gpt = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800677 ret =
678 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
679 &partition_entry_size, &header_size,
680 &max_partition_count);
vijay kumarc8c60a02015-04-28 13:05:04 +0530681 parse_secondary_gpt = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800682 if (ret) {
683 dprintf(CRITICAL,
684 "GPT: Backup signature invalid cannot write GPT\n");
685 goto end;
686 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700687
Ajay Dudanib01e5062011-12-03 23:23:42 -0800688 /* Patching the primary and the backup header of the GPT table */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700689 patch_gpt(gptImage, device_density, partition_entry_array_size,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700690 max_partition_count, partition_entry_size, block_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700691
Ajay Dudanib01e5062011-12-03 23:23:42 -0800692 /* Erasing the eMMC card before writing */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700693 ret = mmc_erase_card(0x00000000, device_density);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800694 if (ret) {
695 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
696 goto end;
697 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700698
Ajay Dudanib01e5062011-12-03 23:23:42 -0800699 /* Writing protective MBR */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700700 ret = mmc_write(0, block_size, (unsigned int *)gptImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800701 if (ret) {
702 dprintf(CRITICAL, "Failed to write Protective MBR\n");
703 goto end;
704 }
705 /* Writing the primary GPT header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700706 primary_header_location = block_size;
707 ret = mmc_write(primary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800708 (unsigned int *)primary_gpt_header);
709 if (ret) {
710 dprintf(CRITICAL, "Failed to write GPT header\n");
711 goto end;
712 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700713
Ajay Dudanib01e5062011-12-03 23:23:42 -0800714 /* Writing the backup GPT header */
715 backup_header_lba = GET_LLWORD_FROM_BYTE
716 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700717 secondary_header_location = backup_header_lba * block_size;
718 ret = mmc_write(secondary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800719 (unsigned int *)secondary_gpt_header);
720 if (ret) {
721 dprintf(CRITICAL, "Failed to write GPT backup header\n");
722 goto end;
723 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700724
Ajay Dudanib01e5062011-12-03 23:23:42 -0800725 /* Writing the partition entries array for the primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700726 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800727 ret = write_gpt_partition_array(primary_gpt_header,
728 partition_entry_array_start,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700729 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800730 if (ret) {
731 dprintf(CRITICAL,
732 "GPT: Could not write GPT Partition entries array\n");
733 goto end;
734 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700735
Ajay Dudanib01e5062011-12-03 23:23:42 -0800736 /*Writing the partition entries array for the backup header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700737 partition_entry_array_start = primary_gpt_header + block_size +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800738 partition_entry_array_size;
739 ret = write_gpt_partition_array(secondary_gpt_header,
740 partition_entry_array_start,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700741 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800742 if (ret) {
743 dprintf(CRITICAL,
744 "GPT: Could not write GPT Partition entries array\n");
745 goto end;
746 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700747
Ajay Dudanib01e5062011-12-03 23:23:42 -0800748 /* Re-read the GPT partition table */
749 dprintf(INFO, "Re-reading the GPT Partition Table\n");
vijay kumarc8c60a02015-04-28 13:05:04 +0530750 flashing_gpt = 0;
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -0800751 partition_count = 0;
752 mmc_read_partition_table(0);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800753 partition_dump();
754 dprintf(CRITICAL, "GPT: Partition Table written\n");
755 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700756
Ajay Dudanib01e5062011-12-03 23:23:42 -0800757 end:
758 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700759}
760
Ajay Dudanib01e5062011-12-03 23:23:42 -0800761unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700762{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700763 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800764 unsigned int partition_type;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700765 uint32_t block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700766
Ajay Dudanib01e5062011-12-03 23:23:42 -0800767 if (partition == 0) {
768 dprintf(CRITICAL, "NULL partition\n");
769 goto end;
770 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700771
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700772 block_size = mmc_get_device_blocksize();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800773 ret = partition_get_type(size, partition, &partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700774 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800775 goto end;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700776
Ajay Dudanib01e5062011-12-03 23:23:42 -0800777 switch (partition_type) {
778 case PARTITION_TYPE_MBR:
779 dprintf(INFO, "Writing MBR partition\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700780 ret = write_mbr(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800781 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700782
Ajay Dudanib01e5062011-12-03 23:23:42 -0800783 case PARTITION_TYPE_GPT:
784 dprintf(INFO, "Writing GPT partition\n");
vijay kumarc8c60a02015-04-28 13:05:04 +0530785 flashing_gpt = 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700786 ret = write_gpt(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800787 dprintf(CRITICAL, "Re-Flash all the partitions\n");
788 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700789
Ajay Dudanib01e5062011-12-03 23:23:42 -0800790 default:
791 dprintf(CRITICAL, "Invalid partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700792 ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800793 goto end;
794 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700795
Ajay Dudanib01e5062011-12-03 23:23:42 -0800796 end:
797 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700798}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800799
Kinson Chikf1a43512011-07-14 11:28:39 -0700800/*
801 * Fill name for android partition found.
802 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800803static void
804mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700805{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800806 switch (type) {
807 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
808 case MBR_MODEM_TYPE:
809 case MBR_MODEM_TYPE2:
810 /* if already assigned last name available then return */
811 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
812 return;
813 strlcpy((char *)partition_ent->name,
814 (const char *)vfat_partitions[vfat_count],
815 sizeof(partition_ent->name));
816 vfat_count++;
817 break;
818 case MBR_SBL1_TYPE:
819 memcpy(partition_ent->name, "sbl1", 4);
820 break;
821 case MBR_SBL2_TYPE:
822 memcpy(partition_ent->name, "sbl2", 4);
823 break;
824 case MBR_SBL3_TYPE:
825 memcpy(partition_ent->name, "sbl3", 4);
826 break;
827 case MBR_RPM_TYPE:
828 memcpy(partition_ent->name, "rpm", 3);
829 break;
830 case MBR_TZ_TYPE:
831 memcpy(partition_ent->name, "tz", 2);
832 break;
833 case MBR_ABOOT_TYPE:
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530834#if PLATFORM_MSM7X27A
835 memcpy(partition_ent->name, "FOTA", 4);
836#else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800837 memcpy(partition_ent->name, "aboot", 5);
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530838#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -0800839 break;
840 case MBR_BOOT_TYPE:
841 memcpy(partition_ent->name, "boot", 4);
842 break;
843 case MBR_MODEM_ST1_TYPE:
844 memcpy(partition_ent->name, "modem_st1", 9);
845 break;
846 case MBR_MODEM_ST2_TYPE:
847 memcpy(partition_ent->name, "modem_st2", 9);
848 break;
849 case MBR_EFS2_TYPE:
850 memcpy(partition_ent->name, "efs2", 4);
851 break;
852 case MBR_USERDATA_TYPE:
853 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
854 return;
855 strlcpy((char *)partition_ent->name,
856 (const char *)ext3_partitions[ext3_count],
857 sizeof(partition_ent->name));
858 ext3_count++;
859 break;
860 case MBR_RECOVERY_TYPE:
861 memcpy(partition_ent->name, "recovery", 8);
862 break;
863 case MBR_MISC_TYPE:
864 memcpy(partition_ent->name, "misc", 4);
865 break;
Neeti Desai2d6b0e42012-03-23 15:48:57 -0700866 case MBR_SSD_TYPE:
867 memcpy(partition_ent->name, "ssd", 3);
868 break;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800869 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700870}
871
872/*
873 * Find index of parition in array of partition entries
874 */
Pavel Nedev285ad922013-04-26 10:39:19 +0300875int partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700876{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800877 unsigned int input_string_length = strlen(name);
878 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700879
neetid6c38de12011-12-02 12:04:50 -0800880 if( partition_count >= NUM_PARTITIONS)
881 {
882 return INVALID_PTN;
883 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800884 for (n = 0; n < partition_count; n++) {
Channagoud Kadabi7768c462015-02-26 11:33:52 -0800885 if ((input_string_length == strlen((const char *)&partition_entries[n].name))
886 && !memcmp(name, &partition_entries[n].name, input_string_length)) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800887 return n;
888 }
889 }
890 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700891}
892
893/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800894unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700895{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700896 uint32_t block_size;
897
898 block_size = mmc_get_device_blocksize();
899
Ajay Dudanib01e5062011-12-03 23:23:42 -0800900 if (index == INVALID_PTN)
901 return 0;
902 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700903 return partition_entries[index].size * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800904 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700905}
906
907/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800908unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700909{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700910 uint32_t block_size;
911
912 block_size = mmc_get_device_blocksize();
913
Ajay Dudanib01e5062011-12-03 23:23:42 -0800914 if (index == INVALID_PTN)
915 return 0;
916 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700917 return partition_entries[index].first_lba * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800918 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700919}
920
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -0800921uint8_t partition_get_lun(int index)
922{
923 return partition_entries[index].lun;
924}
925
Kinson Chikf1a43512011-07-14 11:28:39 -0700926/* Debug: Print all parsed partitions */
927void partition_dump()
928{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800929 unsigned i = 0;
930 for (i = 0; i < partition_count; i++) {
931 dprintf(SPEW,
932 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
933 i, partition_entries[i].name, partition_entries[i].size,
934 partition_entries[i].dtype,
935 partition_entries[i].first_lba,
936 partition_entries[i].last_lba);
937 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700938}
939
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700940static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800941partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700942{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800943 /* Avoid checking past end of buffer */
944 if ((TABLE_SIGNATURE + 1) > size) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700945 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800946 }
947 /* Check to see if signature exists */
948 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
949 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
950 dprintf(CRITICAL, "MBR signature does not match.\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700951 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800952 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700953 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700954}
955
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700956static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800957mbr_partition_get_type(unsigned size, unsigned char *partition,
958 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700959{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800960 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700961
Channagoud Kadabi1921eba2015-03-12 15:14:22 -0700962 if (size < (type_offset + sizeof (*partition_type))) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800963 goto end;
964 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700965
Ajay Dudanib01e5062011-12-03 23:23:42 -0800966 *partition_type = partition[type_offset];
967 end:
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700968 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700969}
970
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700971static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800972partition_get_type(unsigned size, unsigned char *partition,
973 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700974{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700975 unsigned int ret = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700976
Ajay Dudanib01e5062011-12-03 23:23:42 -0800977 /*
978 * If the block contains the MBR signature, then it's likely either
979 * MBR or MBR with protective type (GPT). If the MBR signature is
980 * not there, then it could be the GPT backup.
981 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700982
Ajay Dudanib01e5062011-12-03 23:23:42 -0800983 /* First check the MBR signature */
984 ret = partition_verify_mbr_signature(size, partition);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700985 if (!ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800986 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -0700987
Ajay Dudanib01e5062011-12-03 23:23:42 -0800988 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
989 ret =
990 mbr_partition_get_type(size, partition,
991 &mbr_partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700992 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800993 dprintf(CRITICAL, "Cannot get TYPE of partition");
994 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
995 *partition_type = PARTITION_TYPE_GPT;
996 } else {
997 *partition_type = PARTITION_TYPE_MBR;
998 }
999 } else {
1000 /*
1001 * This could be the GPT backup. Make that assumption for now.
1002 * Anybody who treats the block as GPT backup should check the
1003 * signature.
1004 */
1005 *partition_type = PARTITION_TYPE_GPT_BACKUP;
1006 }
1007 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -07001008}
Kinson Chik4d7444f2011-09-13 15:48:51 -07001009
1010/*
1011 * Parse the gpt header and get the required header fields
1012 * Return 0 on valid signature
1013 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -07001014static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -08001015partition_parse_gpt_header(unsigned char *buffer,
1016 unsigned long long *first_usable_lba,
1017 unsigned int *partition_entry_size,
1018 unsigned int *header_size,
1019 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -07001020{
vijay kumarc8c60a02015-04-28 13:05:04 +05301021 uint32_t crc_val_org = 0;
1022 uint32_t crc_val = 0;
1023 uint32_t ret = 0;
1024 uint32_t partitions_for_block = 0;
1025 uint32_t blocks_to_read = 0;
1026 unsigned char *new_buffer = NULL;
1027 unsigned long long last_usable_lba = 0;
1028 unsigned long long partition_0 = 0;
1029 unsigned long long current_lba = 0;
1030 uint32_t block_size = mmc_get_device_blocksize();
1031 /* Get the density of the mmc device */
1032 uint64_t device_density = mmc_get_device_capacity();
1033
Ajay Dudanib01e5062011-12-03 23:23:42 -08001034 /* Check GPT Signature */
1035 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
1036 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
1037 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001038
Ajay Dudanib01e5062011-12-03 23:23:42 -08001039 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
vijay kumarc8c60a02015-04-28 13:05:04 +05301040 /*check for header size too small*/
1041 if (*header_size < GPT_HEADER_SIZE) {
1042 dprintf(CRITICAL,"GPT Header size is too small\n");
1043 return 1;
1044 }
1045 /*check for header size too large*/
1046 if (*header_size > block_size) {
1047 dprintf(CRITICAL,"GPT Header size is too large\n");
1048 return 1;
1049 }
1050
1051 crc_val_org = GET_LWORD_FROM_BYTE(&buffer[HEADER_CRC_OFFSET]);
1052 /*Write CRC to 0 before we calculate the crc of the GPT header*/
1053 crc_val = 0;
1054 PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);
1055
1056 crc_val = crc32(~0L,buffer, *header_size) ^ (~0L);
1057 if (crc_val != crc_val_org) {
1058 dprintf(CRITICAL,"Header crc mismatch crc_val = %u with crc_val_org = %u\n", crc_val,crc_val_org);
1059 return 1;
1060 }
1061 else
1062 PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);
1063
1064 current_lba =
1065 GET_LLWORD_FROM_BYTE(&buffer[PRIMARY_HEADER_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -08001066 *first_usable_lba =
1067 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
1068 *max_partition_count =
1069 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
1070 *partition_entry_size =
1071 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
vijay kumarc8c60a02015-04-28 13:05:04 +05301072 last_usable_lba =
1073 GET_LLWORD_FROM_BYTE(&buffer[LAST_USABLE_LBA_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -07001074
vijay kumarc8c60a02015-04-28 13:05:04 +05301075 /*current lba and GPT lba should be same*/
1076 if (!parse_secondary_gpt) {
1077 if (current_lba != GPT_LBA) {
1078 dprintf(CRITICAL,"GPT first usable LBA mismatch\n");
1079 return 1;
1080 }
1081 }
1082 /*check for first lba should be with in the valid range*/
1083 if (*first_usable_lba > (device_density/block_size)) {
1084 dprintf(CRITICAL,"Invalid first_usable_lba\n");
1085 return 1;
1086 }
1087 /*check for last lba should be with in the valid range*/
1088 if (last_usable_lba > (device_density/block_size)) {
1089 dprintf(CRITICAL,"Invalid last_usable_lba\n");
1090 return 1;
1091 }
1092 /*check for partition entry size*/
1093 if (*partition_entry_size != PARTITION_ENTRY_SIZE) {
1094 dprintf(CRITICAL,"Invalid parition entry size\n");
1095 return 1;
1096 }
1097
1098 if ((*max_partition_count) > (MIN_PARTITION_ARRAY_SIZE /(*partition_entry_size))) {
1099 dprintf(CRITICAL, "Invalid maximum partition count\n");
1100 return 1;
1101 }
1102
1103 partitions_for_block = block_size / (*partition_entry_size);
1104
1105 blocks_to_read = (*max_partition_count)/ partitions_for_block;
1106 if ((*max_partition_count) % partitions_for_block) {
1107 blocks_to_read += 1;
1108 }
1109
1110 new_buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP((blocks_to_read * block_size),CACHE_LINE));
1111
1112 if (!new_buffer)
1113 {
1114 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
1115 return 1;
1116 }
1117
1118 if (!flashing_gpt) {
1119 partition_0 = GET_LLWORD_FROM_BYTE(&buffer[PARTITION_ENTRIES_OFFSET]);
1120 /*start LBA should always be 2 in primary GPT*/
1121 if(partition_0 != 0x2) {
1122 dprintf(CRITICAL, "Starting LBA mismatch\n");
1123 goto fail;
1124
1125 }
1126 /*read the partition entries to new_buffer*/
1127 ret = mmc_read((partition_0) * (block_size), (unsigned int *)new_buffer, (blocks_to_read * block_size));
1128 if (ret)
1129 {
1130 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
1131 goto fail;
1132 }
1133 crc_val_org = GET_LWORD_FROM_BYTE(&buffer[PARTITION_CRC_OFFSET]);
1134
1135 crc_val = crc32(~0L,new_buffer, ((*max_partition_count) * (*partition_entry_size))) ^ (~0L);
1136 if (crc_val != crc_val_org) {
1137 dprintf(CRITICAL,"Partition entires crc mismatch crc_val= %u with crc_val_org= %u\n",crc_val,crc_val_org);
1138 ret = 1;
1139 }
1140 }
1141fail:
1142 free(new_buffer);
1143 return ret;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001144}
Pavel Nedevb5ba62d2013-07-22 11:57:41 +03001145
1146bool partition_gpt_exists()
1147{
1148 return (gpt_partitions_exist != 0);
1149}