blob: 6c0ae6c4b0fef4709f5da820f37fac8ef308f0ce [file] [log] [blame]
Channagoud Kadabif73aa292013-01-31 16:55:20 -08001/* Copyright (c) 2011-2013, 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>
31#include "mmc.h"
32#include "partition_parser.h"
33
Channagoud Kadabi0e332852013-04-19 12:55:53 -070034static uint32_t mmc_boot_read_gpt();
35static uint32_t mmc_boot_read_mbr();
36static void mbr_fill_name(struct partition_entry *partition_ent,
37 uint32_t type);
38static uint32_t partition_verify_mbr_signature(uint32_t size,
39 uint8_t *buffer);
40static uint32_t mbr_partition_get_type(uint32_t size, uint8_t *partition,
41 uint32_t *partition_type);
42
43static uint32_t partition_get_type(uint32_t size, uint8_t *partition,
44 uint32_t *partition_type);
45static uint32_t partition_parse_gpt_header(uint8_t *buffer,
46 uint64_t *first_usable_lba,
47 uint32_t *partition_entry_size,
48 uint32_t *header_size,
49 uint32_t *max_partition_count);
50
51static uint32_t write_mbr(uint32_t, uint8_t *mbrImage);
52static uint32_t write_gpt(uint32_t size, uint8_t *gptImage);
53
Ajay Dudanib01e5062011-12-03 23:23:42 -080054char *ext3_partitions[] =
55 { "system", "userdata", "persist", "cache", "tombstones" };
56char *vfat_partitions[] = { "modem", "mdm", "NONE" };
57
Kinson Chikf1a43512011-07-14 11:28:39 -070058unsigned int ext3_count = 0;
59unsigned int vfat_count = 0;
60
61struct partition_entry partition_entries[NUM_PARTITIONS];
Pavel Nedevb5ba62d2013-07-22 11:57:41 +030062static unsigned gpt_partitions_exist = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -070063unsigned partition_count = 0;
64
Channagoud Kadabi0e332852013-04-19 12:55:53 -070065unsigned int partition_read_table()
Kinson Chikf1a43512011-07-14 11:28:39 -070066{
Ajay Dudanib01e5062011-12-03 23:23:42 -080067 unsigned int ret;
Kinson Chikf1a43512011-07-14 11:28:39 -070068
Ajay Dudanib01e5062011-12-03 23:23:42 -080069 /* Read MBR of the card */
Channagoud Kadabi0e332852013-04-19 12:55:53 -070070 ret = mmc_boot_read_mbr();
71 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -080072 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -070073 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -080074 }
Kinson Chikf1a43512011-07-14 11:28:39 -070075
Ajay Dudanib01e5062011-12-03 23:23:42 -080076 /* Read GPT of the card if exist */
77 if (gpt_partitions_exist) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -070078 ret = mmc_boot_read_gpt();
79 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -080080 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -070081 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -080082 }
83 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -070084 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -070085}
86
87/*
88 * Read MBR from MMC card and fill partition table.
89 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -070090static unsigned int mmc_boot_read_mbr()
Kinson Chikf1a43512011-07-14 11:28:39 -070091{
Channagoud Kadabi2af6e362013-04-19 14:32:22 -070092 BUF_DMA_ALIGN(buffer, BLOCK_SIZE);
Ajay Dudanib01e5062011-12-03 23:23:42 -080093 unsigned int dtype;
94 unsigned int dfirstsec;
95 unsigned int EBR_first_sec;
96 unsigned int EBR_current_sec;
Channagoud Kadabi0e332852013-04-19 12:55:53 -070097 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -080098 int idx, i;
Kinson Chikf1a43512011-07-14 11:28:39 -070099
Ajay Dudanib01e5062011-12-03 23:23:42 -0800100 /* Print out the MBR first */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700101 ret = mmc_read(0, (unsigned int *)buffer, BLOCK_SIZE);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800102 if (ret) {
103 dprintf(CRITICAL, "Could not read partition from mmc\n");
104 return ret;
105 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700106
Ajay Dudanib01e5062011-12-03 23:23:42 -0800107 /* Check to see if signature exists */
108 ret = partition_verify_mbr_signature(BLOCK_SIZE, buffer);
109 if (ret) {
110 return ret;
111 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700112
Ajay Dudanib01e5062011-12-03 23:23:42 -0800113 /*
114 * Process each of the four partitions in the MBR by reading the table
115 * information into our mbr table.
116 */
117 partition_count = 0;
118 idx = TABLE_ENTRY_0;
119 for (i = 0; i < 4; i++) {
120 /* Type 0xEE indicates end of MBR and GPT partitions exist */
121 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
122 if (dtype == MBR_PROTECTED_TYPE) {
123 gpt_partitions_exist = 1;
124 return ret;
125 }
126 partition_entries[partition_count].dtype = dtype;
127 partition_entries[partition_count].attribute_flag =
128 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
129 partition_entries[partition_count].first_lba =
130 GET_LWORD_FROM_BYTE(&buffer[idx +
131 i * TABLE_ENTRY_SIZE +
132 OFFSET_FIRST_SEC]);
133 partition_entries[partition_count].size =
134 GET_LWORD_FROM_BYTE(&buffer[idx +
135 i * TABLE_ENTRY_SIZE +
136 OFFSET_SIZE]);
137 dfirstsec = partition_entries[partition_count].first_lba;
138 mbr_fill_name(&partition_entries[partition_count],
139 partition_entries[partition_count].dtype);
140 partition_count++;
141 if (partition_count == NUM_PARTITIONS)
142 return ret;
143 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700144
Ajay Dudanib01e5062011-12-03 23:23:42 -0800145 /* See if the last partition is EBR, if not, parsing is done */
146 if (dtype != MBR_EBR_TYPE) {
147 return ret;
148 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700149
Ajay Dudanib01e5062011-12-03 23:23:42 -0800150 EBR_first_sec = dfirstsec;
151 EBR_current_sec = dfirstsec;
Kinson Chikf1a43512011-07-14 11:28:39 -0700152
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700153 ret = mmc_read((EBR_first_sec * 512), (unsigned int *)buffer, BLOCK_SIZE);
154 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800155 return ret;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700156
Ajay Dudanib01e5062011-12-03 23:23:42 -0800157 /* Loop to parse the EBR */
158 for (i = 0;; i++) {
159 ret = partition_verify_mbr_signature(BLOCK_SIZE, buffer);
160 if (ret) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700161 ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800162 break;
163 }
164 partition_entries[partition_count].attribute_flag =
165 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
166 partition_entries[partition_count].dtype =
167 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
168 partition_entries[partition_count].first_lba =
169 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
170 OFFSET_FIRST_SEC]) +
171 EBR_current_sec;
172 partition_entries[partition_count].size =
173 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
174 mbr_fill_name(&(partition_entries[partition_count]),
175 partition_entries[partition_count].dtype);
176 partition_count++;
177 if (partition_count == NUM_PARTITIONS)
178 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700179
Ajay Dudanib01e5062011-12-03 23:23:42 -0800180 dfirstsec =
181 GET_LWORD_FROM_BYTE(&buffer
182 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
183 if (dfirstsec == 0) {
184 /* Getting to the end of the EBR tables */
185 break;
186 }
187 /* More EBR to follow - read in the next EBR sector */
188 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
189 + dfirstsec);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700190 ret = mmc_read(((EBR_first_sec + dfirstsec) * 512),(unsigned int *)buffer,
191 BLOCK_SIZE);
192 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800193 return ret;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700194
Ajay Dudanib01e5062011-12-03 23:23:42 -0800195 EBR_current_sec = EBR_first_sec + dfirstsec;
196 }
197 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700198}
Kinson Chik66552a82011-03-29 15:59:06 -0700199
200/*
201 * Read GPT from MMC and fill partition table
202 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700203static unsigned int mmc_boot_read_gpt()
Kinson Chikf1a43512011-07-14 11:28:39 -0700204{
Channagoud Kadabi2af6e362013-04-19 14:32:22 -0700205 BUF_DMA_ALIGN(data, BLOCK_SIZE);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700206 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800207 unsigned int header_size;
208 unsigned long long first_usable_lba;
209 unsigned long long backup_header_lba;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700210 unsigned long long card_size_sec;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800211 unsigned int max_partition_count = 0;
212 unsigned int partition_entry_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800213 unsigned int i = 0; /* Counter for each 512 block */
214 unsigned int j = 0; /* Counter for each 128 entry in the 512 block */
215 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
216 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
217 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700218 unsigned long long partition_0;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700219 uint64_t device_density;
220
Ajay Dudanib01e5062011-12-03 23:23:42 -0800221 partition_count = 0;
Kinson Chik66552a82011-03-29 15:59:06 -0700222
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700223 /* Get the density of the mmc device */
224
225 device_density = mmc_get_device_capacity();
226
Ajay Dudanib01e5062011-12-03 23:23:42 -0800227 /* Print out the GPT first */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700228 ret = mmc_read(PROTECTIVE_MBR_SIZE, (unsigned int *)data, BLOCK_SIZE);
229 if (ret)
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700230 {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800231 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700232 return ret;
233 }
Kinson Chik66552a82011-03-29 15:59:06 -0700234
Ajay Dudanib01e5062011-12-03 23:23:42 -0800235 ret = partition_parse_gpt_header(data, &first_usable_lba,
236 &partition_entry_size, &header_size,
237 &max_partition_count);
238 if (ret) {
239 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700240
Ajay Dudanib01e5062011-12-03 23:23:42 -0800241 /* Check the backup gpt */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700242
243 /* Get size of MMC */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700244 card_size_sec = (device_density) / BLOCK_SIZE;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700245 ASSERT (card_size_sec > 0);
246
247 backup_header_lba = card_size_sec - 1;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700248 ret = mmc_read((backup_header_lba * BLOCK_SIZE), (unsigned int *)data,
249 BLOCK_SIZE);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700250
Ajay Dudanib01e5062011-12-03 23:23:42 -0800251 if (ret) {
252 dprintf(CRITICAL,
253 "GPT: Could not read backup gpt from mmc\n");
254 return ret;
255 }
Kinson Chik4d7444f2011-09-13 15:48:51 -0700256
Ajay Dudanib01e5062011-12-03 23:23:42 -0800257 ret = partition_parse_gpt_header(data, &first_usable_lba,
258 &partition_entry_size,
259 &header_size,
260 &max_partition_count);
261 if (ret) {
262 dprintf(CRITICAL,
263 "GPT: Primary and backup signatures invalid\n");
264 return ret;
265 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800266 }
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700267 partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800268 /* Read GPT Entries */
Channagoud Kadabi82a482f2013-02-14 21:04:38 -0800269 for (i = 0; i < (ROUNDUP(max_partition_count, 4)) / 4; i++) {
neetid6c38de12011-12-02 12:04:50 -0800270 ASSERT(partition_count < NUM_PARTITIONS);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700271 ret = mmc_read((partition_0 * BLOCK_SIZE) + (i * BLOCK_SIZE),
272 (uint32_t *) data, BLOCK_SIZE);
Kinson Chik66552a82011-03-29 15:59:06 -0700273
Ajay Dudanib01e5062011-12-03 23:23:42 -0800274 if (ret) {
275 dprintf(CRITICAL,
276 "GPT: mmc read card failed reading partition entries.\n");
277 return ret;
278 }
Kinson Chik66552a82011-03-29 15:59:06 -0700279
Ajay Dudanib01e5062011-12-03 23:23:42 -0800280 for (j = 0; j < 4; j++) {
281 memcpy(&(partition_entries[partition_count].type_guid),
282 &data[(j * partition_entry_size)],
283 PARTITION_TYPE_GUID_SIZE);
284 if (partition_entries[partition_count].type_guid[0] ==
285 0x00
286 && partition_entries[partition_count].
287 type_guid[1] == 0x00) {
Channagoud Kadabif73aa292013-01-31 16:55:20 -0800288 i = ROUNDUP(max_partition_count, 4);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800289 break;
290 }
291 memcpy(&
292 (partition_entries[partition_count].
293 unique_partition_guid),
294 &data[(j * partition_entry_size) +
295 UNIQUE_GUID_OFFSET],
296 UNIQUE_PARTITION_GUID_SIZE);
297 partition_entries[partition_count].first_lba =
298 GET_LLWORD_FROM_BYTE(&data
299 [(j * partition_entry_size) +
300 FIRST_LBA_OFFSET]);
301 partition_entries[partition_count].last_lba =
302 GET_LLWORD_FROM_BYTE(&data
303 [(j * partition_entry_size) +
304 LAST_LBA_OFFSET]);
305 partition_entries[partition_count].size =
306 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700307 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800308 partition_entries[partition_count].attribute_flag =
309 GET_LLWORD_FROM_BYTE(&data
310 [(j * partition_entry_size) +
311 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700312
Ajay Dudanib01e5062011-12-03 23:23:42 -0800313 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
314 memcpy(UTF16_name, &data[(j * partition_entry_size) +
315 PARTITION_NAME_OFFSET],
316 MAX_GPT_NAME_SIZE);
317 /*
318 * Currently partition names in *.xml are UTF-8 and lowercase
319 * Only supporting english for now so removing 2nd byte of UTF-16
320 */
321 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
322 partition_entries[partition_count].name[n] =
323 UTF16_name[n * 2];
324 }
325 partition_count++;
326 }
327 }
328 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700329}
330
Neeti Desai5f26aff2011-09-30 10:27:40 -0700331static unsigned int write_mbr_in_blocks(unsigned size, unsigned char *mbrImage)
332{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800333 unsigned int dtype;
334 unsigned int dfirstsec;
335 unsigned int ebrSectorOffset;
336 unsigned char *ebrImage;
337 unsigned char *lastAddress;
338 int idx, i;
339 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700340
Ajay Dudanib01e5062011-12-03 23:23:42 -0800341 /* Write the first block */
342 ret = mmc_write(0, BLOCK_SIZE, (unsigned int *)mbrImage);
343 if (ret) {
344 dprintf(CRITICAL, "Failed to write mbr partition\n");
345 goto end;
346 }
347 dprintf(SPEW, "write of first MBR block ok\n");
348 /*
349 Loop through the MBR table to see if there is an EBR.
350 If found, then figure out where to write the first EBR
351 */
352 idx = TABLE_ENTRY_0;
353 for (i = 0; i < 4; i++) {
354 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
355 if (MBR_EBR_TYPE == dtype) {
356 dprintf(SPEW, "EBR found.\n");
357 break;
358 }
359 }
360 if (MBR_EBR_TYPE != dtype) {
361 dprintf(SPEW, "No EBR in this image\n");
362 goto end;
363 }
364 /* EBR exists. Write each EBR block to mmc */
365 ebrImage = mbrImage + BLOCK_SIZE;
366 ebrSectorOffset =
367 GET_LWORD_FROM_BYTE(&mbrImage
368 [idx + i * TABLE_ENTRY_SIZE +
369 OFFSET_FIRST_SEC]);
370 dfirstsec = 0;
371 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
372 lastAddress = mbrImage + size;
373 while (ebrImage < lastAddress) {
374 dprintf(SPEW, "writing to 0x%X\n",
375 (ebrSectorOffset + dfirstsec) * BLOCK_SIZE);
376 ret =
377 mmc_write((ebrSectorOffset + dfirstsec) * BLOCK_SIZE,
378 BLOCK_SIZE, (unsigned int *)ebrImage);
379 if (ret) {
380 dprintf(CRITICAL,
381 "Failed to write EBR block to sector 0x%X\n",
382 dfirstsec);
383 goto end;
384 }
385 dfirstsec =
386 GET_LWORD_FROM_BYTE(&ebrImage
387 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
388 ebrImage += BLOCK_SIZE;
389 }
390 dprintf(INFO, "MBR written to mmc successfully\n");
391 end:
392 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700393}
394
395/* Write the MBR/EBR to the MMC. */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700396static unsigned int write_mbr(unsigned size, unsigned char *mbrImage)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700397{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800398 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700399
Ajay Dudanib01e5062011-12-03 23:23:42 -0800400 /* Verify that passed in block is a valid MBR */
401 ret = partition_verify_mbr_signature(size, mbrImage);
402 if (ret) {
403 goto end;
404 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700405
Ajay Dudanib01e5062011-12-03 23:23:42 -0800406 /* Write the MBR/EBR to mmc */
407 ret = write_mbr_in_blocks(size, mbrImage);
408 if (ret) {
409 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
410 goto end;
411 }
412 /* Re-read the MBR partition into mbr table */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700413 ret = mmc_boot_read_mbr();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800414 if (ret) {
415 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
416 goto end;
417 }
418 partition_dump();
419 end:
420 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700421}
422
423/*
424 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
425*/
426int reflect(int data, int len)
427{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800428 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700429
Ajay Dudanib01e5062011-12-03 23:23:42 -0800430 for (int i = 0; i < len; i++) {
431 if (data & 0x1) {
432 ref |= (1 << ((len - 1) - i));
433 }
434 data = (data >> 1);
435 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700436
Ajay Dudanib01e5062011-12-03 23:23:42 -0800437 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700438}
439
440/*
441* Function to calculate the CRC32
442*/
443unsigned int calculate_crc32(unsigned char *buffer, int len)
444{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800445 int byte_length = 8; /*length of unit (i.e. byte) */
446 int msb = 0;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700447 int polynomial = 0x04C11DB7; /* IEEE 32bit polynomial */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800448 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
449 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
450 int regs_msb = 0;
451 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700452
Ajay Dudanib01e5062011-12-03 23:23:42 -0800453 for (int i = 0; i < len; i++) {
454 int data_byte = buffer[i];
455 data_byte = reflect(data_byte, 8);
456 for (int j = 0; j < byte_length; j++) {
457 msb = data_byte >> (byte_length - 1); /* get MSB */
458 msb &= 1; /* ensure just 1 bit */
459 regs_msb = (regs >> 31) & 1; /* MSB of regs */
460 regs = regs << 1; /* shift regs for CRC-CCITT */
461 if (regs_msb ^ msb) { /* MSB is a 1 */
462 regs = regs ^ polynomial; /* XOR with generator poly */
463 }
464 regs = regs & regs_mask; /* Mask off excess upper bits */
465 data_byte <<= 1; /* get to next bit */
466 }
467 }
468 regs = regs & regs_mask;
469 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700470
Ajay Dudanib01e5062011-12-03 23:23:42 -0800471 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700472}
473
474/*
475 * Write the GPT Partition Entry Array to the MMC.
476 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800477static unsigned int
478write_gpt_partition_array(unsigned char *header,
479 unsigned int partition_array_start,
480 unsigned int array_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700481{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700482 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800483 unsigned long long partition_entry_lba;
484 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700485
Ajay Dudanib01e5062011-12-03 23:23:42 -0800486 partition_entry_lba =
487 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
488 partition_entry_array_start_location = partition_entry_lba * BLOCK_SIZE;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700489
Ajay Dudanib01e5062011-12-03 23:23:42 -0800490 ret = mmc_write(partition_entry_array_start_location, array_size,
491 (unsigned int *)partition_array_start);
492 if (ret) {
493 dprintf(CRITICAL,
494 "GPT: FAILED to write the partition entry array\n");
495 goto end;
496 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700497
Ajay Dudanib01e5062011-12-03 23:23:42 -0800498 end:
499 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700500}
501
Ajay Dudanib01e5062011-12-03 23:23:42 -0800502static void
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700503patch_gpt(unsigned char *gptImage, uint64_t density, unsigned int array_size,
504 unsigned int max_part_count, unsigned int part_entry_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700505{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800506 unsigned int partition_entry_array_start;
507 unsigned char *primary_gpt_header;
508 unsigned char *secondary_gpt_header;
509 unsigned int offset;
510 unsigned long long card_size_sec;
511 int total_part = 0;
512 unsigned int last_part_offset;
513 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700514
Ajay Dudanib01e5062011-12-03 23:23:42 -0800515 /* Get size of MMC */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700516 card_size_sec = (density) / 512;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800517 /* Working around cap at 4GB */
518 if (card_size_sec == 0) {
519 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
520 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700521
Ajay Dudanib01e5062011-12-03 23:23:42 -0800522 /* Patching primary header */
523 primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
524 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
525 ((long long)(card_size_sec - 1)));
526 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
527 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700528
Ajay Dudanib01e5062011-12-03 23:23:42 -0800529 /* Patching backup GPT */
530 offset = (2 * array_size);
531 secondary_gpt_header = offset + BLOCK_SIZE + primary_gpt_header;
532 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
533 ((long long)(card_size_sec - 1)));
534 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
535 ((long long)(card_size_sec - 34)));
536 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
537 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700538
Ajay Dudanib01e5062011-12-03 23:23:42 -0800539 /* Find last partition */
540 while (*(primary_gpt_header + BLOCK_SIZE + total_part * ENTRY_SIZE) !=
541 0) {
542 total_part++;
543 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700544
Ajay Dudanib01e5062011-12-03 23:23:42 -0800545 /* Patching last partition */
546 last_part_offset =
547 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
548 PUT_LONG_LONG(primary_gpt_header + BLOCK_SIZE + last_part_offset,
549 (long long)(card_size_sec - 34));
550 PUT_LONG_LONG(primary_gpt_header + BLOCK_SIZE + last_part_offset +
551 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700552
Ajay Dudanib01e5062011-12-03 23:23:42 -0800553 /* Updating CRC of the Partition entry array in both headers */
554 partition_entry_array_start = primary_gpt_header + BLOCK_SIZE;
555 crc_value = calculate_crc32(partition_entry_array_start,
556 max_part_count * part_entry_size);
557 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700558
Ajay Dudanib01e5062011-12-03 23:23:42 -0800559 crc_value = calculate_crc32(partition_entry_array_start + array_size,
560 max_part_count * part_entry_size);
561 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700562
Ajay Dudanib01e5062011-12-03 23:23:42 -0800563 /* Clearing CRC fields to calculate */
564 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
565 crc_value = calculate_crc32(primary_gpt_header, 92);
566 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700567
Ajay Dudanib01e5062011-12-03 23:23:42 -0800568 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
569 crc_value = (calculate_crc32(secondary_gpt_header, 92));
570 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700571
572}
573
574/*
575 * Write the GPT to the MMC.
576 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700577static unsigned int write_gpt(unsigned size, unsigned char *gptImage)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700578{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700579 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800580 unsigned int header_size;
581 unsigned long long first_usable_lba;
582 unsigned long long backup_header_lba;
583 unsigned int max_partition_count = 0;
584 unsigned int partition_entry_size;
585 unsigned int partition_entry_array_start;
586 unsigned char *primary_gpt_header;
587 unsigned char *secondary_gpt_header;
588 unsigned int offset;
589 unsigned int partition_entry_array_size;
590 unsigned long long primary_header_location; /* address on the emmc card */
591 unsigned long long secondary_header_location; /* address on the emmc card */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700592 uint64_t device_density;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700593
Ajay Dudanib01e5062011-12-03 23:23:42 -0800594 /* Verify that passed block has a valid GPT primary header */
595 primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
596 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
597 &partition_entry_size, &header_size,
598 &max_partition_count);
599 if (ret) {
600 dprintf(CRITICAL,
601 "GPT: Primary signature invalid cannot write GPT\n");
602 goto end;
603 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700604
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700605 /* Get the density of the mmc device */
606
607 device_density = mmc_get_device_capacity();
608
Ajay Dudanib01e5062011-12-03 23:23:42 -0800609 /* Verify that passed block has a valid backup GPT HEADER */
610 partition_entry_array_size = partition_entry_size * max_partition_count;
611 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
612 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
613 }
614 offset = (2 * partition_entry_array_size);
615 secondary_gpt_header = offset + BLOCK_SIZE + primary_gpt_header;
616 ret =
617 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
618 &partition_entry_size, &header_size,
619 &max_partition_count);
620 if (ret) {
621 dprintf(CRITICAL,
622 "GPT: Backup signature invalid cannot write GPT\n");
623 goto end;
624 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700625
Ajay Dudanib01e5062011-12-03 23:23:42 -0800626 /* Patching the primary and the backup header of the GPT table */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700627 patch_gpt(gptImage, device_density, partition_entry_array_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800628 max_partition_count, partition_entry_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700629
Ajay Dudanib01e5062011-12-03 23:23:42 -0800630 /* Erasing the eMMC card before writing */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700631 ret = mmc_erase_card(0x00000000, device_density);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800632 if (ret) {
633 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
634 goto end;
635 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700636
Ajay Dudanib01e5062011-12-03 23:23:42 -0800637 /* Writing protective MBR */
638 ret = mmc_write(0, PROTECTIVE_MBR_SIZE, (unsigned int *)gptImage);
639 if (ret) {
640 dprintf(CRITICAL, "Failed to write Protective MBR\n");
641 goto end;
642 }
643 /* Writing the primary GPT header */
644 primary_header_location = PROTECTIVE_MBR_SIZE;
645 ret = mmc_write(primary_header_location, BLOCK_SIZE,
646 (unsigned int *)primary_gpt_header);
647 if (ret) {
648 dprintf(CRITICAL, "Failed to write GPT header\n");
649 goto end;
650 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700651
Ajay Dudanib01e5062011-12-03 23:23:42 -0800652 /* Writing the backup GPT header */
653 backup_header_lba = GET_LLWORD_FROM_BYTE
654 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
655 secondary_header_location = backup_header_lba * BLOCK_SIZE;
656 ret = mmc_write(secondary_header_location, BLOCK_SIZE,
657 (unsigned int *)secondary_gpt_header);
658 if (ret) {
659 dprintf(CRITICAL, "Failed to write GPT backup header\n");
660 goto end;
661 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700662
Ajay Dudanib01e5062011-12-03 23:23:42 -0800663 /* Writing the partition entries array for the primary header */
664 partition_entry_array_start = primary_gpt_header + BLOCK_SIZE;
665 ret = write_gpt_partition_array(primary_gpt_header,
666 partition_entry_array_start,
667 partition_entry_array_size);
668 if (ret) {
669 dprintf(CRITICAL,
670 "GPT: Could not write GPT Partition entries array\n");
671 goto end;
672 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700673
Ajay Dudanib01e5062011-12-03 23:23:42 -0800674 /*Writing the partition entries array for the backup header */
675 partition_entry_array_start = primary_gpt_header + BLOCK_SIZE +
676 partition_entry_array_size;
677 ret = write_gpt_partition_array(secondary_gpt_header,
678 partition_entry_array_start,
679 partition_entry_array_size);
680 if (ret) {
681 dprintf(CRITICAL,
682 "GPT: Could not write GPT Partition entries array\n");
683 goto end;
684 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700685
Ajay Dudanib01e5062011-12-03 23:23:42 -0800686 /* Re-read the GPT partition table */
687 dprintf(INFO, "Re-reading the GPT Partition Table\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700688 ret = mmc_boot_read_gpt();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800689 if (ret) {
690 dprintf(CRITICAL,
691 "GPT: Failure to re- read the GPT Partition table\n");
692 goto end;
693 }
694 partition_dump();
695 dprintf(CRITICAL, "GPT: Partition Table written\n");
696 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700697
Ajay Dudanib01e5062011-12-03 23:23:42 -0800698 end:
699 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700700}
701
Ajay Dudanib01e5062011-12-03 23:23:42 -0800702unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700703{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700704 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800705 unsigned int partition_type;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700706
Ajay Dudanib01e5062011-12-03 23:23:42 -0800707 if (partition == 0) {
708 dprintf(CRITICAL, "NULL partition\n");
709 goto end;
710 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700711
Ajay Dudanib01e5062011-12-03 23:23:42 -0800712 ret = partition_get_type(size, partition, &partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700713 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800714 goto end;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700715
Ajay Dudanib01e5062011-12-03 23:23:42 -0800716 switch (partition_type) {
717 case PARTITION_TYPE_MBR:
718 dprintf(INFO, "Writing MBR partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700719 ret = write_mbr(size, partition);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800720 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700721
Ajay Dudanib01e5062011-12-03 23:23:42 -0800722 case PARTITION_TYPE_GPT:
723 dprintf(INFO, "Writing GPT partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700724 ret = write_gpt(size, partition);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800725 dprintf(CRITICAL, "Re-Flash all the partitions\n");
726 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700727
Ajay Dudanib01e5062011-12-03 23:23:42 -0800728 default:
729 dprintf(CRITICAL, "Invalid partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700730 ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800731 goto end;
732 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700733
Ajay Dudanib01e5062011-12-03 23:23:42 -0800734 end:
735 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700736}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800737
Kinson Chikf1a43512011-07-14 11:28:39 -0700738/*
739 * Fill name for android partition found.
740 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800741static void
742mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700743{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800744 switch (type) {
745 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
746 case MBR_MODEM_TYPE:
747 case MBR_MODEM_TYPE2:
748 /* if already assigned last name available then return */
749 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
750 return;
751 strlcpy((char *)partition_ent->name,
752 (const char *)vfat_partitions[vfat_count],
753 sizeof(partition_ent->name));
754 vfat_count++;
755 break;
756 case MBR_SBL1_TYPE:
757 memcpy(partition_ent->name, "sbl1", 4);
758 break;
759 case MBR_SBL2_TYPE:
760 memcpy(partition_ent->name, "sbl2", 4);
761 break;
762 case MBR_SBL3_TYPE:
763 memcpy(partition_ent->name, "sbl3", 4);
764 break;
765 case MBR_RPM_TYPE:
766 memcpy(partition_ent->name, "rpm", 3);
767 break;
768 case MBR_TZ_TYPE:
769 memcpy(partition_ent->name, "tz", 2);
770 break;
771 case MBR_ABOOT_TYPE:
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530772#if PLATFORM_MSM7X27A
773 memcpy(partition_ent->name, "FOTA", 4);
774#else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800775 memcpy(partition_ent->name, "aboot", 5);
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530776#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -0800777 break;
778 case MBR_BOOT_TYPE:
779 memcpy(partition_ent->name, "boot", 4);
780 break;
781 case MBR_MODEM_ST1_TYPE:
782 memcpy(partition_ent->name, "modem_st1", 9);
783 break;
784 case MBR_MODEM_ST2_TYPE:
785 memcpy(partition_ent->name, "modem_st2", 9);
786 break;
787 case MBR_EFS2_TYPE:
788 memcpy(partition_ent->name, "efs2", 4);
789 break;
790 case MBR_USERDATA_TYPE:
791 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
792 return;
793 strlcpy((char *)partition_ent->name,
794 (const char *)ext3_partitions[ext3_count],
795 sizeof(partition_ent->name));
796 ext3_count++;
797 break;
798 case MBR_RECOVERY_TYPE:
799 memcpy(partition_ent->name, "recovery", 8);
800 break;
801 case MBR_MISC_TYPE:
802 memcpy(partition_ent->name, "misc", 4);
803 break;
Neeti Desai2d6b0e42012-03-23 15:48:57 -0700804 case MBR_SSD_TYPE:
805 memcpy(partition_ent->name, "ssd", 3);
806 break;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800807 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700808}
809
810/*
811 * Find index of parition in array of partition entries
812 */
Pavel Nedev285ad922013-04-26 10:39:19 +0300813int partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700814{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800815 unsigned int input_string_length = strlen(name);
816 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700817
neetid6c38de12011-12-02 12:04:50 -0800818 if( partition_count >= NUM_PARTITIONS)
819 {
820 return INVALID_PTN;
821 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800822 for (n = 0; n < partition_count; n++) {
823 if (!memcmp
824 (name, &partition_entries[n].name, input_string_length)
825 && input_string_length ==
826 strlen((const char *)&partition_entries[n].name)) {
827 return n;
828 }
829 }
830 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700831}
832
833/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800834unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700835{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800836 if (index == INVALID_PTN)
837 return 0;
838 else {
839 return partition_entries[index].size * BLOCK_SIZE;
840 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700841}
842
843/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800844unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700845{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800846 if (index == INVALID_PTN)
847 return 0;
848 else {
849 return partition_entries[index].first_lba * BLOCK_SIZE;
850 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700851}
852
853/* Debug: Print all parsed partitions */
854void partition_dump()
855{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800856 unsigned i = 0;
857 for (i = 0; i < partition_count; i++) {
858 dprintf(SPEW,
859 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
860 i, partition_entries[i].name, partition_entries[i].size,
861 partition_entries[i].dtype,
862 partition_entries[i].first_lba,
863 partition_entries[i].last_lba);
864 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700865}
866
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700867static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800868partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700869{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800870 /* Avoid checking past end of buffer */
871 if ((TABLE_SIGNATURE + 1) > size) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700872 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800873 }
874 /* Check to see if signature exists */
875 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
876 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
877 dprintf(CRITICAL, "MBR signature does not match.\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700878 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800879 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700880 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700881}
882
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700883static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800884mbr_partition_get_type(unsigned size, unsigned char *partition,
885 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700886{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800887 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700888
Ajay Dudanib01e5062011-12-03 23:23:42 -0800889 if (size < type_offset) {
890 goto end;
891 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700892
Ajay Dudanib01e5062011-12-03 23:23:42 -0800893 *partition_type = partition[type_offset];
894 end:
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700895 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700896}
897
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700898static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800899partition_get_type(unsigned size, unsigned char *partition,
900 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700901{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700902 unsigned int ret = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700903
Ajay Dudanib01e5062011-12-03 23:23:42 -0800904 /*
905 * If the block contains the MBR signature, then it's likely either
906 * MBR or MBR with protective type (GPT). If the MBR signature is
907 * not there, then it could be the GPT backup.
908 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700909
Ajay Dudanib01e5062011-12-03 23:23:42 -0800910 /* First check the MBR signature */
911 ret = partition_verify_mbr_signature(size, partition);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700912 if (!ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800913 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -0700914
Ajay Dudanib01e5062011-12-03 23:23:42 -0800915 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
916 ret =
917 mbr_partition_get_type(size, partition,
918 &mbr_partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700919 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800920 dprintf(CRITICAL, "Cannot get TYPE of partition");
921 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
922 *partition_type = PARTITION_TYPE_GPT;
923 } else {
924 *partition_type = PARTITION_TYPE_MBR;
925 }
926 } else {
927 /*
928 * This could be the GPT backup. Make that assumption for now.
929 * Anybody who treats the block as GPT backup should check the
930 * signature.
931 */
932 *partition_type = PARTITION_TYPE_GPT_BACKUP;
933 }
934 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700935}
Kinson Chik4d7444f2011-09-13 15:48:51 -0700936
937/*
938 * Parse the gpt header and get the required header fields
939 * Return 0 on valid signature
940 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700941static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800942partition_parse_gpt_header(unsigned char *buffer,
943 unsigned long long *first_usable_lba,
944 unsigned int *partition_entry_size,
945 unsigned int *header_size,
946 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -0700947{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800948 /* Check GPT Signature */
949 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
950 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
951 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -0700952
Ajay Dudanib01e5062011-12-03 23:23:42 -0800953 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
954 *first_usable_lba =
955 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
956 *max_partition_count =
957 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
958 *partition_entry_size =
959 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700960
Ajay Dudanib01e5062011-12-03 23:23:42 -0800961 return 0;
Kinson Chik4d7444f2011-09-13 15:48:51 -0700962}
Pavel Nedevb5ba62d2013-07-22 11:57:41 +0300963
964bool partition_gpt_exists()
965{
966 return (gpt_partitions_exist != 0);
967}