blob: 3f678b552ca75c50f58a3dccd9d805b9d0a190fa [file] [log] [blame]
Mayank Grover3c3253e2018-05-30 16:33:33 +05301/* Copyright (c) 2011-2013, 2015, 2018 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;
Mayank Grover3c3253e2018-05-30 16:33:33 +053088/* this is a pointer to ptn_entries_buffer */
89static unsigned char *new_buffer = NULL;
Kinson Chikf1a43512011-07-14 11:28:39 -070090
Channagoud Kadabi0e332852013-04-19 12:55:53 -070091unsigned int partition_read_table()
Kinson Chikf1a43512011-07-14 11:28:39 -070092{
Ajay Dudanib01e5062011-12-03 23:23:42 -080093 unsigned int ret;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070094 uint32_t block_size;
95
96 block_size = mmc_get_device_blocksize();
Kinson Chikf1a43512011-07-14 11:28:39 -070097
Channagoud Kadabie9b94022013-11-12 13:49:41 -080098 /* Allocate partition entries array */
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -080099 if(!partition_entries)
100 {
101 partition_entries = (struct partition_entry *) calloc(NUM_PARTITIONS, sizeof(struct partition_entry));
102 ASSERT(partition_entries);
103 }
Channagoud Kadabie9b94022013-11-12 13:49:41 -0800104
Ajay Dudanib01e5062011-12-03 23:23:42 -0800105 /* Read MBR of the card */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700106 ret = mmc_boot_read_mbr(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700107 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800108 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700109 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800110 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700111
Ajay Dudanib01e5062011-12-03 23:23:42 -0800112 /* Read GPT of the card if exist */
113 if (gpt_partitions_exist) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700114 ret = mmc_boot_read_gpt(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700115 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800116 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700117 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800118 }
119 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700120 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700121}
122
123/*
124 * Read MBR from MMC card and fill partition table.
125 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700126static unsigned int mmc_boot_read_mbr(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700127{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700128 uint8_t *buffer = NULL;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800129 unsigned int dtype;
130 unsigned int dfirstsec;
131 unsigned int EBR_first_sec;
132 unsigned int EBR_current_sec;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700133 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800134 int idx, i;
Kinson Chikf1a43512011-07-14 11:28:39 -0700135
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700136 buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
137
138 if (!buffer)
139 {
140 dprintf(CRITICAL, "Error allocating memory while reading partition table\n");
141 ret = -1;
142 goto end;
143 }
144
Ajay Dudanib01e5062011-12-03 23:23:42 -0800145 /* Print out the MBR first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700146 ret = mmc_read(0, (unsigned int *)buffer, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800147 if (ret) {
148 dprintf(CRITICAL, "Could not read partition from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700149 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800150 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700151
Ajay Dudanib01e5062011-12-03 23:23:42 -0800152 /* Check to see if signature exists */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700153 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800154 if (ret) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700155 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800156 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700157
Ajay Dudanib01e5062011-12-03 23:23:42 -0800158 /*
159 * Process each of the four partitions in the MBR by reading the table
160 * information into our mbr table.
161 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800162 idx = TABLE_ENTRY_0;
163 for (i = 0; i < 4; i++) {
164 /* Type 0xEE indicates end of MBR and GPT partitions exist */
165 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
166 if (dtype == MBR_PROTECTED_TYPE) {
167 gpt_partitions_exist = 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700168 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800169 }
170 partition_entries[partition_count].dtype = dtype;
171 partition_entries[partition_count].attribute_flag =
172 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
173 partition_entries[partition_count].first_lba =
174 GET_LWORD_FROM_BYTE(&buffer[idx +
175 i * TABLE_ENTRY_SIZE +
176 OFFSET_FIRST_SEC]);
177 partition_entries[partition_count].size =
178 GET_LWORD_FROM_BYTE(&buffer[idx +
179 i * TABLE_ENTRY_SIZE +
180 OFFSET_SIZE]);
181 dfirstsec = partition_entries[partition_count].first_lba;
182 mbr_fill_name(&partition_entries[partition_count],
183 partition_entries[partition_count].dtype);
184 partition_count++;
185 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700186 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800187 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700188
Ajay Dudanib01e5062011-12-03 23:23:42 -0800189 /* See if the last partition is EBR, if not, parsing is done */
190 if (dtype != MBR_EBR_TYPE) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700191 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800192 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700193
Ajay Dudanib01e5062011-12-03 23:23:42 -0800194 EBR_first_sec = dfirstsec;
195 EBR_current_sec = dfirstsec;
Kinson Chikf1a43512011-07-14 11:28:39 -0700196
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700197 ret = mmc_read((EBR_first_sec * block_size), (unsigned int *)buffer, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700198 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700199 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700200
Ajay Dudanib01e5062011-12-03 23:23:42 -0800201 /* Loop to parse the EBR */
202 for (i = 0;; i++) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700203 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800204 if (ret) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700205 ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800206 break;
207 }
208 partition_entries[partition_count].attribute_flag =
209 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
210 partition_entries[partition_count].dtype =
211 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
212 partition_entries[partition_count].first_lba =
213 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
214 OFFSET_FIRST_SEC]) +
215 EBR_current_sec;
216 partition_entries[partition_count].size =
217 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
218 mbr_fill_name(&(partition_entries[partition_count]),
219 partition_entries[partition_count].dtype);
220 partition_count++;
221 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700222 goto end;
Kinson Chikf1a43512011-07-14 11:28:39 -0700223
Ajay Dudanib01e5062011-12-03 23:23:42 -0800224 dfirstsec =
225 GET_LWORD_FROM_BYTE(&buffer
226 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
227 if (dfirstsec == 0) {
228 /* Getting to the end of the EBR tables */
229 break;
230 }
231 /* More EBR to follow - read in the next EBR sector */
232 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
233 + dfirstsec);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700234 ret = mmc_read(((EBR_first_sec + dfirstsec) * block_size),(unsigned int *)buffer,
235 block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700236 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700237 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700238
Ajay Dudanib01e5062011-12-03 23:23:42 -0800239 EBR_current_sec = EBR_first_sec + dfirstsec;
240 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700241end:
242 if (buffer)
243 free(buffer);
244
Ajay Dudanib01e5062011-12-03 23:23:42 -0800245 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700246}
Kinson Chik66552a82011-03-29 15:59:06 -0700247
248/*
249 * Read GPT from MMC and fill partition table
250 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700251static unsigned int mmc_boot_read_gpt(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700252{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700253 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800254 unsigned int header_size;
255 unsigned long long first_usable_lba;
256 unsigned long long backup_header_lba;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700257 unsigned long long card_size_sec;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800258 unsigned int max_partition_count = 0;
259 unsigned int partition_entry_size;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700260 unsigned int i = 0; /* Counter for each block */
261 unsigned int j = 0; /* Counter for each entry in a block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800262 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
263 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
264 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700265 uint64_t device_density;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700266 uint8_t *data = NULL;
Mayank Grover3c3253e2018-05-30 16:33:33 +0530267 uint8_t *data_org_ptr = NULL;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700268 uint32_t part_entry_cnt = block_size / ENTRY_SIZE;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700269
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700270 /* Get the density of the mmc device */
271
272 device_density = mmc_get_device_capacity();
273
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700274 data = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
275 if (!data)
276 {
277 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
278 ret = -1;
279 goto end;
280 }
Mayank Grover3c3253e2018-05-30 16:33:33 +0530281 data_org_ptr = data;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700282
Ajay Dudanib01e5062011-12-03 23:23:42 -0800283 /* Print out the GPT first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700284 ret = mmc_read(block_size, (unsigned int *)data, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700285 if (ret)
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700286 {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800287 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700288 goto end;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700289 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800290 ret = partition_parse_gpt_header(data, &first_usable_lba,
291 &partition_entry_size, &header_size,
292 &max_partition_count);
293 if (ret) {
294 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700295
Ajay Dudanib01e5062011-12-03 23:23:42 -0800296 /* Check the backup gpt */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700297
298 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700299 card_size_sec = (device_density) / block_size;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700300 ASSERT (card_size_sec > 0);
301
302 backup_header_lba = card_size_sec - 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700303 ret = mmc_read((backup_header_lba * block_size), (unsigned int *)data,
304 block_size);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700305
Ajay Dudanib01e5062011-12-03 23:23:42 -0800306 if (ret) {
307 dprintf(CRITICAL,
308 "GPT: Could not read backup gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700309 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800310 }
vijay kumarfe623342015-07-22 12:42:06 +0530311 parse_secondary_gpt = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800312 ret = partition_parse_gpt_header(data, &first_usable_lba,
313 &partition_entry_size,
314 &header_size,
315 &max_partition_count);
316 if (ret) {
317 dprintf(CRITICAL,
318 "GPT: Primary and backup signatures invalid\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700319 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800320 }
vijay kumarfe623342015-07-22 12:42:06 +0530321 parse_secondary_gpt = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800322 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800323 /* Read GPT Entries */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700324 for (i = 0; i < (ROUNDUP(max_partition_count, part_entry_cnt)) / part_entry_cnt; i++) {
neetid6c38de12011-12-02 12:04:50 -0800325 ASSERT(partition_count < NUM_PARTITIONS);
Mayank Grover3c3253e2018-05-30 16:33:33 +0530326
327 data = (new_buffer + (i * block_size));
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700328 for (j = 0; j < part_entry_cnt; j++) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800329 memcpy(&(partition_entries[partition_count].type_guid),
330 &data[(j * partition_entry_size)],
331 PARTITION_TYPE_GUID_SIZE);
332 if (partition_entries[partition_count].type_guid[0] ==
333 0x00
334 && partition_entries[partition_count].
335 type_guid[1] == 0x00) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700336 i = ROUNDUP(max_partition_count, part_entry_cnt);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800337 break;
338 }
339 memcpy(&
340 (partition_entries[partition_count].
341 unique_partition_guid),
342 &data[(j * partition_entry_size) +
343 UNIQUE_GUID_OFFSET],
344 UNIQUE_PARTITION_GUID_SIZE);
345 partition_entries[partition_count].first_lba =
346 GET_LLWORD_FROM_BYTE(&data
347 [(j * partition_entry_size) +
348 FIRST_LBA_OFFSET]);
349 partition_entries[partition_count].last_lba =
350 GET_LLWORD_FROM_BYTE(&data
351 [(j * partition_entry_size) +
352 LAST_LBA_OFFSET]);
353 partition_entries[partition_count].size =
354 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700355 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800356 partition_entries[partition_count].attribute_flag =
357 GET_LLWORD_FROM_BYTE(&data
358 [(j * partition_entry_size) +
359 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700360
Ajay Dudanib01e5062011-12-03 23:23:42 -0800361 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
362 memcpy(UTF16_name, &data[(j * partition_entry_size) +
363 PARTITION_NAME_OFFSET],
364 MAX_GPT_NAME_SIZE);
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -0800365 partition_entries[partition_count].lun = mmc_get_lun();
366
Ajay Dudanib01e5062011-12-03 23:23:42 -0800367 /*
368 * Currently partition names in *.xml are UTF-8 and lowercase
369 * Only supporting english for now so removing 2nd byte of UTF-16
370 */
371 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
372 partition_entries[partition_count].name[n] =
373 UTF16_name[n * 2];
374 }
375 partition_count++;
376 }
377 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700378end:
Mayank Grover3c3253e2018-05-30 16:33:33 +0530379 if (data_org_ptr)
380 free(data_org_ptr);
381 if (new_buffer)
382 free(new_buffer);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700383
Ajay Dudanib01e5062011-12-03 23:23:42 -0800384 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700385}
386
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700387static unsigned int write_mbr_in_blocks(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700388{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800389 unsigned int dtype;
390 unsigned int dfirstsec;
391 unsigned int ebrSectorOffset;
392 unsigned char *ebrImage;
393 unsigned char *lastAddress;
394 int idx, i;
395 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700396
Ajay Dudanib01e5062011-12-03 23:23:42 -0800397 /* Write the first block */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700398 ret = mmc_write(0, block_size, (unsigned int *)mbrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800399 if (ret) {
400 dprintf(CRITICAL, "Failed to write mbr partition\n");
401 goto end;
402 }
403 dprintf(SPEW, "write of first MBR block ok\n");
404 /*
405 Loop through the MBR table to see if there is an EBR.
406 If found, then figure out where to write the first EBR
407 */
408 idx = TABLE_ENTRY_0;
409 for (i = 0; i < 4; i++) {
410 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
411 if (MBR_EBR_TYPE == dtype) {
412 dprintf(SPEW, "EBR found.\n");
413 break;
414 }
415 }
416 if (MBR_EBR_TYPE != dtype) {
417 dprintf(SPEW, "No EBR in this image\n");
418 goto end;
419 }
420 /* EBR exists. Write each EBR block to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700421 ebrImage = mbrImage + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800422 ebrSectorOffset =
423 GET_LWORD_FROM_BYTE(&mbrImage
424 [idx + i * TABLE_ENTRY_SIZE +
425 OFFSET_FIRST_SEC]);
426 dfirstsec = 0;
427 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
428 lastAddress = mbrImage + size;
429 while (ebrImage < lastAddress) {
430 dprintf(SPEW, "writing to 0x%X\n",
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700431 (ebrSectorOffset + dfirstsec) * block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800432 ret =
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700433 mmc_write((ebrSectorOffset + dfirstsec) * block_size,
434 block_size, (unsigned int *)ebrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800435 if (ret) {
436 dprintf(CRITICAL,
437 "Failed to write EBR block to sector 0x%X\n",
438 dfirstsec);
439 goto end;
440 }
441 dfirstsec =
442 GET_LWORD_FROM_BYTE(&ebrImage
443 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700444 ebrImage += block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800445 }
446 dprintf(INFO, "MBR written to mmc successfully\n");
447 end:
448 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700449}
450
451/* Write the MBR/EBR to the MMC. */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700452static unsigned int write_mbr(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700453{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800454 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700455
Ajay Dudanib01e5062011-12-03 23:23:42 -0800456 /* Verify that passed in block is a valid MBR */
457 ret = partition_verify_mbr_signature(size, mbrImage);
458 if (ret) {
459 goto end;
460 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700461
Ajay Dudanib01e5062011-12-03 23:23:42 -0800462 /* Write the MBR/EBR to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700463 ret = write_mbr_in_blocks(size, mbrImage, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800464 if (ret) {
465 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
466 goto end;
467 }
468 /* Re-read the MBR partition into mbr table */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700469 ret = mmc_boot_read_mbr(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800470 if (ret) {
471 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
472 goto end;
473 }
474 partition_dump();
475 end:
476 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700477}
478
479/*
480 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
481*/
482int reflect(int data, int len)
483{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800484 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700485
Ajay Dudanib01e5062011-12-03 23:23:42 -0800486 for (int i = 0; i < len; i++) {
487 if (data & 0x1) {
488 ref |= (1 << ((len - 1) - i));
489 }
490 data = (data >> 1);
491 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700492
Ajay Dudanib01e5062011-12-03 23:23:42 -0800493 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700494}
495
496/*
497* Function to calculate the CRC32
498*/
499unsigned int calculate_crc32(unsigned char *buffer, int len)
500{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800501 int byte_length = 8; /*length of unit (i.e. byte) */
502 int msb = 0;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700503 int polynomial = 0x04C11DB7; /* IEEE 32bit polynomial */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800504 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
505 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
506 int regs_msb = 0;
507 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700508
Ajay Dudanib01e5062011-12-03 23:23:42 -0800509 for (int i = 0; i < len; i++) {
510 int data_byte = buffer[i];
511 data_byte = reflect(data_byte, 8);
512 for (int j = 0; j < byte_length; j++) {
513 msb = data_byte >> (byte_length - 1); /* get MSB */
514 msb &= 1; /* ensure just 1 bit */
515 regs_msb = (regs >> 31) & 1; /* MSB of regs */
516 regs = regs << 1; /* shift regs for CRC-CCITT */
517 if (regs_msb ^ msb) { /* MSB is a 1 */
518 regs = regs ^ polynomial; /* XOR with generator poly */
519 }
520 regs = regs & regs_mask; /* Mask off excess upper bits */
521 data_byte <<= 1; /* get to next bit */
522 }
523 }
524 regs = regs & regs_mask;
525 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700526
Ajay Dudanib01e5062011-12-03 23:23:42 -0800527 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700528}
529
530/*
531 * Write the GPT Partition Entry Array to the MMC.
532 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800533static unsigned int
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700534write_gpt_partition_array(uint8_t *header,
535 uint32_t partition_array_start,
536 uint32_t array_size,
537 uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700538{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700539 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800540 unsigned long long partition_entry_lba;
541 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700542
Ajay Dudanib01e5062011-12-03 23:23:42 -0800543 partition_entry_lba =
544 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700545 partition_entry_array_start_location = partition_entry_lba * block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700546
Ajay Dudanib01e5062011-12-03 23:23:42 -0800547 ret = mmc_write(partition_entry_array_start_location, array_size,
548 (unsigned int *)partition_array_start);
549 if (ret) {
550 dprintf(CRITICAL,
551 "GPT: FAILED to write the partition entry array\n");
552 goto end;
553 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700554
Ajay Dudanib01e5062011-12-03 23:23:42 -0800555 end:
556 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700557}
558
Ajay Dudanib01e5062011-12-03 23:23:42 -0800559static void
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700560patch_gpt(uint8_t *gptImage, uint64_t density, uint32_t array_size,
561 uint32_t max_part_count, uint32_t part_entry_size, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700562{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800563 unsigned int partition_entry_array_start;
564 unsigned char *primary_gpt_header;
565 unsigned char *secondary_gpt_header;
566 unsigned int offset;
567 unsigned long long card_size_sec;
568 int total_part = 0;
569 unsigned int last_part_offset;
570 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700571
Ajay Dudanib01e5062011-12-03 23:23:42 -0800572 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700573 card_size_sec = (density) / block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800574 /* Working around cap at 4GB */
575 if (card_size_sec == 0) {
576 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
577 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700578
Ajay Dudanib01e5062011-12-03 23:23:42 -0800579 /* Patching primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700580 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800581 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
582 ((long long)(card_size_sec - 1)));
583 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
584 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700585
Ajay Dudanib01e5062011-12-03 23:23:42 -0800586 /* Patching backup GPT */
587 offset = (2 * array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700588 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800589 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
590 ((long long)(card_size_sec - 1)));
591 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
592 ((long long)(card_size_sec - 34)));
593 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
594 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700595
Ajay Dudanib01e5062011-12-03 23:23:42 -0800596 /* Find last partition */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700597 while (*(primary_gpt_header + block_size + total_part * ENTRY_SIZE) !=
Ajay Dudanib01e5062011-12-03 23:23:42 -0800598 0) {
599 total_part++;
600 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700601
Ajay Dudanib01e5062011-12-03 23:23:42 -0800602 /* Patching last partition */
603 last_part_offset =
604 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700605 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800606 (long long)(card_size_sec - 34));
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700607 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800608 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700609
Ajay Dudanib01e5062011-12-03 23:23:42 -0800610 /* Updating CRC of the Partition entry array in both headers */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700611 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800612 crc_value = calculate_crc32(partition_entry_array_start,
613 max_part_count * part_entry_size);
614 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700615
Ajay Dudanib01e5062011-12-03 23:23:42 -0800616 crc_value = calculate_crc32(partition_entry_array_start + array_size,
617 max_part_count * part_entry_size);
618 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700619
Ajay Dudanib01e5062011-12-03 23:23:42 -0800620 /* Clearing CRC fields to calculate */
621 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
622 crc_value = calculate_crc32(primary_gpt_header, 92);
623 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700624
Ajay Dudanib01e5062011-12-03 23:23:42 -0800625 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
626 crc_value = (calculate_crc32(secondary_gpt_header, 92));
627 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700628
629}
630
631/*
632 * Write the GPT to the MMC.
633 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700634static unsigned int write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700635{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700636 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800637 unsigned int header_size;
638 unsigned long long first_usable_lba;
639 unsigned long long backup_header_lba;
640 unsigned int max_partition_count = 0;
641 unsigned int partition_entry_size;
642 unsigned int partition_entry_array_start;
643 unsigned char *primary_gpt_header;
644 unsigned char *secondary_gpt_header;
645 unsigned int offset;
646 unsigned int partition_entry_array_size;
647 unsigned long long primary_header_location; /* address on the emmc card */
648 unsigned long long secondary_header_location; /* address on the emmc card */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700649 uint64_t device_density;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700650
Ajay Dudanib01e5062011-12-03 23:23:42 -0800651 /* Verify that passed block has a valid GPT primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700652 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800653 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
654 &partition_entry_size, &header_size,
655 &max_partition_count);
656 if (ret) {
657 dprintf(CRITICAL,
658 "GPT: Primary signature invalid cannot write GPT\n");
659 goto end;
660 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700661
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700662 /* Get the density of the mmc device */
663
664 device_density = mmc_get_device_capacity();
665
Ajay Dudanib01e5062011-12-03 23:23:42 -0800666 /* Verify that passed block has a valid backup GPT HEADER */
667 partition_entry_array_size = partition_entry_size * max_partition_count;
668 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
669 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
670 }
671 offset = (2 * partition_entry_array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700672 secondary_gpt_header = offset + block_size + primary_gpt_header;
vijay kumarc8c60a02015-04-28 13:05:04 +0530673 parse_secondary_gpt = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800674 ret =
675 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
676 &partition_entry_size, &header_size,
677 &max_partition_count);
vijay kumarc8c60a02015-04-28 13:05:04 +0530678 parse_secondary_gpt = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800679 if (ret) {
680 dprintf(CRITICAL,
681 "GPT: Backup signature invalid cannot write GPT\n");
682 goto end;
683 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700684
Ajay Dudanib01e5062011-12-03 23:23:42 -0800685 /* Patching the primary and the backup header of the GPT table */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700686 patch_gpt(gptImage, device_density, partition_entry_array_size,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700687 max_partition_count, partition_entry_size, block_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700688
Ajay Dudanib01e5062011-12-03 23:23:42 -0800689 /* Erasing the eMMC card before writing */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700690 ret = mmc_erase_card(0x00000000, device_density);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800691 if (ret) {
692 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
693 goto end;
694 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700695
Ajay Dudanib01e5062011-12-03 23:23:42 -0800696 /* Writing protective MBR */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700697 ret = mmc_write(0, block_size, (unsigned int *)gptImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800698 if (ret) {
699 dprintf(CRITICAL, "Failed to write Protective MBR\n");
700 goto end;
701 }
702 /* Writing the primary GPT header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700703 primary_header_location = block_size;
704 ret = mmc_write(primary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800705 (unsigned int *)primary_gpt_header);
706 if (ret) {
707 dprintf(CRITICAL, "Failed to write GPT header\n");
708 goto end;
709 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700710
Ajay Dudanib01e5062011-12-03 23:23:42 -0800711 /* Writing the backup GPT header */
712 backup_header_lba = GET_LLWORD_FROM_BYTE
713 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700714 secondary_header_location = backup_header_lba * block_size;
715 ret = mmc_write(secondary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800716 (unsigned int *)secondary_gpt_header);
717 if (ret) {
718 dprintf(CRITICAL, "Failed to write GPT backup header\n");
719 goto end;
720 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700721
Ajay Dudanib01e5062011-12-03 23:23:42 -0800722 /* Writing the partition entries array for the primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700723 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800724 ret = write_gpt_partition_array(primary_gpt_header,
725 partition_entry_array_start,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700726 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800727 if (ret) {
728 dprintf(CRITICAL,
729 "GPT: Could not write GPT Partition entries array\n");
730 goto end;
731 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700732
Ajay Dudanib01e5062011-12-03 23:23:42 -0800733 /*Writing the partition entries array for the backup header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700734 partition_entry_array_start = primary_gpt_header + block_size +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800735 partition_entry_array_size;
736 ret = write_gpt_partition_array(secondary_gpt_header,
737 partition_entry_array_start,
Channagoud Kadabi57eb6302013-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 /* Re-read the GPT partition table */
746 dprintf(INFO, "Re-reading the GPT Partition Table\n");
vijay kumarc8c60a02015-04-28 13:05:04 +0530747 flashing_gpt = 0;
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -0800748 partition_count = 0;
749 mmc_read_partition_table(0);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800750 partition_dump();
751 dprintf(CRITICAL, "GPT: Partition Table written\n");
752 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700753
Ajay Dudanib01e5062011-12-03 23:23:42 -0800754 end:
755 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700756}
757
Ajay Dudanib01e5062011-12-03 23:23:42 -0800758unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700759{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700760 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800761 unsigned int partition_type;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700762 uint32_t block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700763
Ajay Dudanib01e5062011-12-03 23:23:42 -0800764 if (partition == 0) {
765 dprintf(CRITICAL, "NULL partition\n");
766 goto end;
767 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700768
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700769 block_size = mmc_get_device_blocksize();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800770 ret = partition_get_type(size, partition, &partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700771 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800772 goto end;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700773
Ajay Dudanib01e5062011-12-03 23:23:42 -0800774 switch (partition_type) {
775 case PARTITION_TYPE_MBR:
776 dprintf(INFO, "Writing MBR partition\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700777 ret = write_mbr(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800778 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700779
Ajay Dudanib01e5062011-12-03 23:23:42 -0800780 case PARTITION_TYPE_GPT:
781 dprintf(INFO, "Writing GPT partition\n");
vijay kumarc8c60a02015-04-28 13:05:04 +0530782 flashing_gpt = 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700783 ret = write_gpt(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800784 dprintf(CRITICAL, "Re-Flash all the partitions\n");
785 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700786
Ajay Dudanib01e5062011-12-03 23:23:42 -0800787 default:
788 dprintf(CRITICAL, "Invalid partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700789 ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800790 goto end;
791 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700792
Ajay Dudanib01e5062011-12-03 23:23:42 -0800793 end:
794 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700795}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800796
Kinson Chikf1a43512011-07-14 11:28:39 -0700797/*
798 * Fill name for android partition found.
799 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800800static void
801mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700802{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800803 switch (type) {
804 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
805 case MBR_MODEM_TYPE:
806 case MBR_MODEM_TYPE2:
807 /* if already assigned last name available then return */
808 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
809 return;
810 strlcpy((char *)partition_ent->name,
811 (const char *)vfat_partitions[vfat_count],
812 sizeof(partition_ent->name));
813 vfat_count++;
814 break;
815 case MBR_SBL1_TYPE:
816 memcpy(partition_ent->name, "sbl1", 4);
817 break;
818 case MBR_SBL2_TYPE:
819 memcpy(partition_ent->name, "sbl2", 4);
820 break;
821 case MBR_SBL3_TYPE:
822 memcpy(partition_ent->name, "sbl3", 4);
823 break;
824 case MBR_RPM_TYPE:
825 memcpy(partition_ent->name, "rpm", 3);
826 break;
827 case MBR_TZ_TYPE:
828 memcpy(partition_ent->name, "tz", 2);
829 break;
830 case MBR_ABOOT_TYPE:
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530831#if PLATFORM_MSM7X27A
832 memcpy(partition_ent->name, "FOTA", 4);
833#else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800834 memcpy(partition_ent->name, "aboot", 5);
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530835#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -0800836 break;
837 case MBR_BOOT_TYPE:
838 memcpy(partition_ent->name, "boot", 4);
839 break;
840 case MBR_MODEM_ST1_TYPE:
841 memcpy(partition_ent->name, "modem_st1", 9);
842 break;
843 case MBR_MODEM_ST2_TYPE:
844 memcpy(partition_ent->name, "modem_st2", 9);
845 break;
846 case MBR_EFS2_TYPE:
847 memcpy(partition_ent->name, "efs2", 4);
848 break;
849 case MBR_USERDATA_TYPE:
850 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
851 return;
852 strlcpy((char *)partition_ent->name,
853 (const char *)ext3_partitions[ext3_count],
854 sizeof(partition_ent->name));
855 ext3_count++;
856 break;
857 case MBR_RECOVERY_TYPE:
858 memcpy(partition_ent->name, "recovery", 8);
859 break;
860 case MBR_MISC_TYPE:
861 memcpy(partition_ent->name, "misc", 4);
862 break;
Neeti Desai2d6b0e42012-03-23 15:48:57 -0700863 case MBR_SSD_TYPE:
864 memcpy(partition_ent->name, "ssd", 3);
865 break;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800866 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700867}
868
869/*
870 * Find index of parition in array of partition entries
871 */
Pavel Nedev285ad922013-04-26 10:39:19 +0300872int partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700873{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800874 unsigned int input_string_length = strlen(name);
875 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700876
neetid6c38de12011-12-02 12:04:50 -0800877 if( partition_count >= NUM_PARTITIONS)
878 {
879 return INVALID_PTN;
880 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800881 for (n = 0; n < partition_count; n++) {
Channagoud Kadabi7768c462015-02-26 11:33:52 -0800882 if ((input_string_length == strlen((const char *)&partition_entries[n].name))
883 && !memcmp(name, &partition_entries[n].name, input_string_length)) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800884 return n;
885 }
886 }
887 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700888}
889
890/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800891unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700892{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700893 uint32_t block_size;
894
895 block_size = mmc_get_device_blocksize();
896
Ajay Dudanib01e5062011-12-03 23:23:42 -0800897 if (index == INVALID_PTN)
898 return 0;
899 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700900 return partition_entries[index].size * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800901 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700902}
903
904/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800905unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700906{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700907 uint32_t block_size;
908
909 block_size = mmc_get_device_blocksize();
910
Ajay Dudanib01e5062011-12-03 23:23:42 -0800911 if (index == INVALID_PTN)
912 return 0;
913 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700914 return partition_entries[index].first_lba * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800915 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700916}
917
Sundarajan Srinivasan4ab741f2013-12-04 17:14:37 -0800918uint8_t partition_get_lun(int index)
919{
920 return partition_entries[index].lun;
921}
922
Kinson Chikf1a43512011-07-14 11:28:39 -0700923/* Debug: Print all parsed partitions */
924void partition_dump()
925{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800926 unsigned i = 0;
927 for (i = 0; i < partition_count; i++) {
928 dprintf(SPEW,
929 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
930 i, partition_entries[i].name, partition_entries[i].size,
931 partition_entries[i].dtype,
932 partition_entries[i].first_lba,
933 partition_entries[i].last_lba);
934 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700935}
936
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700937static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800938partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700939{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800940 /* Avoid checking past end of buffer */
941 if ((TABLE_SIGNATURE + 1) > size) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700942 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800943 }
944 /* Check to see if signature exists */
945 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
946 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
947 dprintf(CRITICAL, "MBR signature does not match.\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700948 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800949 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700950 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700951}
952
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700953static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800954mbr_partition_get_type(unsigned size, unsigned char *partition,
955 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700956{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800957 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700958
Channagoud Kadabi1921eba2015-03-12 15:14:22 -0700959 if (size < (type_offset + sizeof (*partition_type))) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800960 goto end;
961 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700962
Ajay Dudanib01e5062011-12-03 23:23:42 -0800963 *partition_type = partition[type_offset];
964 end:
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700965 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700966}
967
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700968static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800969partition_get_type(unsigned size, unsigned char *partition,
970 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700971{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700972 unsigned int ret = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700973
Ajay Dudanib01e5062011-12-03 23:23:42 -0800974 /*
975 * If the block contains the MBR signature, then it's likely either
976 * MBR or MBR with protective type (GPT). If the MBR signature is
977 * not there, then it could be the GPT backup.
978 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700979
Ajay Dudanib01e5062011-12-03 23:23:42 -0800980 /* First check the MBR signature */
981 ret = partition_verify_mbr_signature(size, partition);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700982 if (!ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800983 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -0700984
Ajay Dudanib01e5062011-12-03 23:23:42 -0800985 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
986 ret =
987 mbr_partition_get_type(size, partition,
988 &mbr_partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700989 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800990 dprintf(CRITICAL, "Cannot get TYPE of partition");
991 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
992 *partition_type = PARTITION_TYPE_GPT;
993 } else {
994 *partition_type = PARTITION_TYPE_MBR;
995 }
996 } else {
997 /*
998 * This could be the GPT backup. Make that assumption for now.
999 * Anybody who treats the block as GPT backup should check the
1000 * signature.
1001 */
1002 *partition_type = PARTITION_TYPE_GPT_BACKUP;
1003 }
1004 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -07001005}
Kinson Chik4d7444f2011-09-13 15:48:51 -07001006
1007/*
1008 * Parse the gpt header and get the required header fields
1009 * Return 0 on valid signature
1010 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -07001011static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -08001012partition_parse_gpt_header(unsigned char *buffer,
1013 unsigned long long *first_usable_lba,
1014 unsigned int *partition_entry_size,
1015 unsigned int *header_size,
1016 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -07001017{
vijay kumarc8c60a02015-04-28 13:05:04 +05301018 uint32_t crc_val_org = 0;
1019 uint32_t crc_val = 0;
1020 uint32_t ret = 0;
1021 uint32_t partitions_for_block = 0;
1022 uint32_t blocks_to_read = 0;
vijay kumarc8c60a02015-04-28 13:05:04 +05301023 unsigned long long last_usable_lba = 0;
1024 unsigned long long partition_0 = 0;
1025 unsigned long long current_lba = 0;
1026 uint32_t block_size = mmc_get_device_blocksize();
1027 /* Get the density of the mmc device */
1028 uint64_t device_density = mmc_get_device_capacity();
1029
Ajay Dudanib01e5062011-12-03 23:23:42 -08001030 /* Check GPT Signature */
1031 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
1032 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
1033 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001034
Ajay Dudanib01e5062011-12-03 23:23:42 -08001035 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
vijay kumarc8c60a02015-04-28 13:05:04 +05301036 /*check for header size too small*/
1037 if (*header_size < GPT_HEADER_SIZE) {
1038 dprintf(CRITICAL,"GPT Header size is too small\n");
1039 return 1;
1040 }
1041 /*check for header size too large*/
1042 if (*header_size > block_size) {
1043 dprintf(CRITICAL,"GPT Header size is too large\n");
1044 return 1;
1045 }
1046
1047 crc_val_org = GET_LWORD_FROM_BYTE(&buffer[HEADER_CRC_OFFSET]);
1048 /*Write CRC to 0 before we calculate the crc of the GPT header*/
1049 crc_val = 0;
1050 PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);
1051
1052 crc_val = crc32(~0L,buffer, *header_size) ^ (~0L);
1053 if (crc_val != crc_val_org) {
1054 dprintf(CRITICAL,"Header crc mismatch crc_val = %u with crc_val_org = %u\n", crc_val,crc_val_org);
1055 return 1;
1056 }
1057 else
1058 PUT_LONG(&buffer[HEADER_CRC_OFFSET], crc_val);
1059
1060 current_lba =
1061 GET_LLWORD_FROM_BYTE(&buffer[PRIMARY_HEADER_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -08001062 *first_usable_lba =
1063 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
1064 *max_partition_count =
1065 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
1066 *partition_entry_size =
1067 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
vijay kumarc8c60a02015-04-28 13:05:04 +05301068 last_usable_lba =
1069 GET_LLWORD_FROM_BYTE(&buffer[LAST_USABLE_LBA_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -07001070
vijay kumarc8c60a02015-04-28 13:05:04 +05301071 /*current lba and GPT lba should be same*/
1072 if (!parse_secondary_gpt) {
1073 if (current_lba != GPT_LBA) {
1074 dprintf(CRITICAL,"GPT first usable LBA mismatch\n");
1075 return 1;
1076 }
1077 }
1078 /*check for first lba should be with in the valid range*/
1079 if (*first_usable_lba > (device_density/block_size)) {
1080 dprintf(CRITICAL,"Invalid first_usable_lba\n");
1081 return 1;
1082 }
1083 /*check for last lba should be with in the valid range*/
1084 if (last_usable_lba > (device_density/block_size)) {
1085 dprintf(CRITICAL,"Invalid last_usable_lba\n");
1086 return 1;
1087 }
1088 /*check for partition entry size*/
1089 if (*partition_entry_size != PARTITION_ENTRY_SIZE) {
1090 dprintf(CRITICAL,"Invalid parition entry size\n");
1091 return 1;
1092 }
1093
1094 if ((*max_partition_count) > (MIN_PARTITION_ARRAY_SIZE /(*partition_entry_size))) {
1095 dprintf(CRITICAL, "Invalid maximum partition count\n");
1096 return 1;
1097 }
1098
1099 partitions_for_block = block_size / (*partition_entry_size);
1100
1101 blocks_to_read = (*max_partition_count)/ partitions_for_block;
1102 if ((*max_partition_count) % partitions_for_block) {
1103 blocks_to_read += 1;
1104 }
1105
1106 new_buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP((blocks_to_read * block_size),CACHE_LINE));
1107
1108 if (!new_buffer)
1109 {
1110 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
1111 return 1;
1112 }
1113
1114 if (!flashing_gpt) {
1115 partition_0 = GET_LLWORD_FROM_BYTE(&buffer[PARTITION_ENTRIES_OFFSET]);
1116 /*start LBA should always be 2 in primary GPT*/
1117 if(partition_0 != 0x2) {
1118 dprintf(CRITICAL, "Starting LBA mismatch\n");
1119 goto fail;
1120
1121 }
1122 /*read the partition entries to new_buffer*/
1123 ret = mmc_read((partition_0) * (block_size), (unsigned int *)new_buffer, (blocks_to_read * block_size));
1124 if (ret)
1125 {
1126 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
1127 goto fail;
1128 }
1129 crc_val_org = GET_LWORD_FROM_BYTE(&buffer[PARTITION_CRC_OFFSET]);
1130
1131 crc_val = crc32(~0L,new_buffer, ((*max_partition_count) * (*partition_entry_size))) ^ (~0L);
1132 if (crc_val != crc_val_org) {
1133 dprintf(CRITICAL,"Partition entires crc mismatch crc_val= %u with crc_val_org= %u\n",crc_val,crc_val_org);
1134 ret = 1;
1135 }
Mayank Grover3c3253e2018-05-30 16:33:33 +05301136 return ret;
vijay kumarc8c60a02015-04-28 13:05:04 +05301137 }
1138fail:
1139 free(new_buffer);
1140 return ret;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001141}
Pavel Nedevb5ba62d2013-07-22 11:57:41 +03001142
1143bool partition_gpt_exists()
1144{
1145 return (gpt_partitions_exist != 0);
1146}