blob: b607f3b8faafa6127d17cdd3c0f083f79a12ebd5 [file] [log] [blame]
Neeti Desaice6ad9a2012-03-21 18:57:59 -07001/* Copyright (c) 2011-2012, Code Aurora Forum. 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.
12 * * Neither the name of Code Aurora Forum, Inc. nor the names of its
13 * 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
Ajay Dudanib01e5062011-12-03 23:23:42 -080034char *ext3_partitions[] =
35 { "system", "userdata", "persist", "cache", "tombstones" };
36char *vfat_partitions[] = { "modem", "mdm", "NONE" };
37
Kinson Chikf1a43512011-07-14 11:28:39 -070038unsigned int ext3_count = 0;
39unsigned int vfat_count = 0;
40
41struct partition_entry partition_entries[NUM_PARTITIONS];
42unsigned gpt_partitions_exist = 0;
43unsigned partition_count = 0;
44
45//TODO: Remove the dependency of mmc in these functions
Ajay Dudanib01e5062011-12-03 23:23:42 -080046unsigned int
47partition_read_table(struct mmc_boot_host *mmc_host,
48 struct mmc_boot_card *mmc_card)
Kinson Chikf1a43512011-07-14 11:28:39 -070049{
Ajay Dudanib01e5062011-12-03 23:23:42 -080050 unsigned int ret;
Kinson Chikf1a43512011-07-14 11:28:39 -070051
Ajay Dudanib01e5062011-12-03 23:23:42 -080052 /* Read MBR of the card */
53 ret = mmc_boot_read_mbr(mmc_host, mmc_card);
54 if (ret != MMC_BOOT_E_SUCCESS) {
55 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
56 return MMC_BOOT_E_FAILURE;
57 }
Kinson Chikf1a43512011-07-14 11:28:39 -070058
Ajay Dudanib01e5062011-12-03 23:23:42 -080059 /* Read GPT of the card if exist */
60 if (gpt_partitions_exist) {
61 ret = mmc_boot_read_gpt(mmc_host, mmc_card);
62 if (ret != MMC_BOOT_E_SUCCESS) {
63 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
64 return MMC_BOOT_E_FAILURE;
65 }
66 }
67 return MMC_BOOT_E_SUCCESS;
Kinson Chikf1a43512011-07-14 11:28:39 -070068}
69
70/*
71 * Read MBR from MMC card and fill partition table.
72 */
Ajay Dudanib01e5062011-12-03 23:23:42 -080073unsigned int
74mmc_boot_read_mbr(struct mmc_boot_host *mmc_host,
75 struct mmc_boot_card *mmc_card)
Kinson Chikf1a43512011-07-14 11:28:39 -070076{
Ajay Dudanib01e5062011-12-03 23:23:42 -080077 unsigned char buffer[BLOCK_SIZE];
78 unsigned int dtype;
79 unsigned int dfirstsec;
80 unsigned int EBR_first_sec;
81 unsigned int EBR_current_sec;
82 int ret = MMC_BOOT_E_SUCCESS;
83 int idx, i;
Kinson Chikf1a43512011-07-14 11:28:39 -070084
Ajay Dudanib01e5062011-12-03 23:23:42 -080085 /* Print out the MBR first */
86 ret = mmc_boot_read_from_card(mmc_host, mmc_card, 0,
87 BLOCK_SIZE, (unsigned int *)buffer);
88 if (ret) {
89 dprintf(CRITICAL, "Could not read partition from mmc\n");
90 return ret;
91 }
Kinson Chikf1a43512011-07-14 11:28:39 -070092
Ajay Dudanib01e5062011-12-03 23:23:42 -080093 /* Check to see if signature exists */
94 ret = partition_verify_mbr_signature(BLOCK_SIZE, buffer);
95 if (ret) {
96 return ret;
97 }
Kinson Chikf1a43512011-07-14 11:28:39 -070098
Ajay Dudanib01e5062011-12-03 23:23:42 -080099 /*
100 * Process each of the four partitions in the MBR by reading the table
101 * information into our mbr table.
102 */
103 partition_count = 0;
104 idx = TABLE_ENTRY_0;
105 for (i = 0; i < 4; i++) {
106 /* Type 0xEE indicates end of MBR and GPT partitions exist */
107 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
108 if (dtype == MBR_PROTECTED_TYPE) {
109 gpt_partitions_exist = 1;
110 return ret;
111 }
112 partition_entries[partition_count].dtype = dtype;
113 partition_entries[partition_count].attribute_flag =
114 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
115 partition_entries[partition_count].first_lba =
116 GET_LWORD_FROM_BYTE(&buffer[idx +
117 i * TABLE_ENTRY_SIZE +
118 OFFSET_FIRST_SEC]);
119 partition_entries[partition_count].size =
120 GET_LWORD_FROM_BYTE(&buffer[idx +
121 i * TABLE_ENTRY_SIZE +
122 OFFSET_SIZE]);
123 dfirstsec = partition_entries[partition_count].first_lba;
124 mbr_fill_name(&partition_entries[partition_count],
125 partition_entries[partition_count].dtype);
126 partition_count++;
127 if (partition_count == NUM_PARTITIONS)
128 return ret;
129 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700130
Ajay Dudanib01e5062011-12-03 23:23:42 -0800131 /* See if the last partition is EBR, if not, parsing is done */
132 if (dtype != MBR_EBR_TYPE) {
133 return ret;
134 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700135
Ajay Dudanib01e5062011-12-03 23:23:42 -0800136 EBR_first_sec = dfirstsec;
137 EBR_current_sec = dfirstsec;
Kinson Chikf1a43512011-07-14 11:28:39 -0700138
Ajay Dudanib01e5062011-12-03 23:23:42 -0800139 ret = mmc_boot_read_from_card(mmc_host, mmc_card,
140 (EBR_first_sec * 512),
141 BLOCK_SIZE, (unsigned int *)buffer);
142 if (ret) {
143 return ret;
144 }
145 /* Loop to parse the EBR */
146 for (i = 0;; i++) {
147 ret = partition_verify_mbr_signature(BLOCK_SIZE, buffer);
148 if (ret) {
149 ret = MMC_BOOT_E_SUCCESS;
150 break;
151 }
152 partition_entries[partition_count].attribute_flag =
153 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
154 partition_entries[partition_count].dtype =
155 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
156 partition_entries[partition_count].first_lba =
157 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
158 OFFSET_FIRST_SEC]) +
159 EBR_current_sec;
160 partition_entries[partition_count].size =
161 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
162 mbr_fill_name(&(partition_entries[partition_count]),
163 partition_entries[partition_count].dtype);
164 partition_count++;
165 if (partition_count == NUM_PARTITIONS)
166 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700167
Ajay Dudanib01e5062011-12-03 23:23:42 -0800168 dfirstsec =
169 GET_LWORD_FROM_BYTE(&buffer
170 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
171 if (dfirstsec == 0) {
172 /* Getting to the end of the EBR tables */
173 break;
174 }
175 /* More EBR to follow - read in the next EBR sector */
176 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
177 + dfirstsec);
178 ret = mmc_boot_read_from_card(mmc_host, mmc_card,
179 ((EBR_first_sec +
180 dfirstsec) * 512), BLOCK_SIZE,
181 (unsigned int *)buffer);
182 if (ret) {
183 return ret;
184 }
185 EBR_current_sec = EBR_first_sec + dfirstsec;
186 }
187 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700188}
Kinson Chik66552a82011-03-29 15:59:06 -0700189
190/*
191 * Read GPT from MMC and fill partition table
192 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800193unsigned int
194mmc_boot_read_gpt(struct mmc_boot_host *mmc_host,
195 struct mmc_boot_card *mmc_card)
Kinson Chikf1a43512011-07-14 11:28:39 -0700196{
Kinson Chik66552a82011-03-29 15:59:06 -0700197
Ajay Dudanib01e5062011-12-03 23:23:42 -0800198 int ret = MMC_BOOT_E_SUCCESS;
199 unsigned int header_size;
200 unsigned long long first_usable_lba;
201 unsigned long long backup_header_lba;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700202 unsigned long long card_size_sec;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800203 unsigned int max_partition_count = 0;
204 unsigned int partition_entry_size;
205 unsigned char data[BLOCK_SIZE];
206 unsigned int i = 0; /* Counter for each 512 block */
207 unsigned int j = 0; /* Counter for each 128 entry in the 512 block */
208 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
209 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
210 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700211 unsigned long long partition_0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800212 partition_count = 0;
Kinson Chik66552a82011-03-29 15:59:06 -0700213
Ajay Dudanib01e5062011-12-03 23:23:42 -0800214 /* Print out the GPT first */
215 ret = mmc_boot_read_from_card(mmc_host, mmc_card,
216 PROTECTIVE_MBR_SIZE,
217 BLOCK_SIZE, (unsigned int *)data);
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700218 if (ret){
Ajay Dudanib01e5062011-12-03 23:23:42 -0800219 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700220 }
Kinson Chik66552a82011-03-29 15:59:06 -0700221
Ajay Dudanib01e5062011-12-03 23:23:42 -0800222 ret = partition_parse_gpt_header(data, &first_usable_lba,
223 &partition_entry_size, &header_size,
224 &max_partition_count);
225 if (ret) {
226 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700227
Ajay Dudanib01e5062011-12-03 23:23:42 -0800228 /* Check the backup gpt */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700229
230 /* Get size of MMC */
231 card_size_sec = (mmc_card->capacity) / BLOCK_SIZE;
232 ASSERT (card_size_sec > 0);
233
234 backup_header_lba = card_size_sec - 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800235 ret =
236 mmc_boot_read_from_card(mmc_host, mmc_card,
237 (backup_header_lba * BLOCK_SIZE),
238 BLOCK_SIZE, (unsigned int *)data);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700239
Ajay Dudanib01e5062011-12-03 23:23:42 -0800240 if (ret) {
241 dprintf(CRITICAL,
242 "GPT: Could not read backup gpt from mmc\n");
243 return ret;
244 }
Kinson Chik4d7444f2011-09-13 15:48:51 -0700245
Ajay Dudanib01e5062011-12-03 23:23:42 -0800246 ret = partition_parse_gpt_header(data, &first_usable_lba,
247 &partition_entry_size,
248 &header_size,
249 &max_partition_count);
250 if (ret) {
251 dprintf(CRITICAL,
252 "GPT: Primary and backup signatures invalid\n");
253 return ret;
254 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800255 }
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700256 partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800257 /* Read GPT Entries */
258 for (i = 0; i < (max_partition_count / 4); i++) {
neetid6c38de12011-12-02 12:04:50 -0800259 ASSERT(partition_count < NUM_PARTITIONS);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800260 ret = mmc_boot_read_from_card(mmc_host, mmc_card,
261 (partition_0 * BLOCK_SIZE) +
262 (i * BLOCK_SIZE),
263 BLOCK_SIZE, (uint32_t *) data);
Kinson Chik66552a82011-03-29 15:59:06 -0700264
Ajay Dudanib01e5062011-12-03 23:23:42 -0800265 if (ret) {
266 dprintf(CRITICAL,
267 "GPT: mmc read card failed reading partition entries.\n");
268 return ret;
269 }
Kinson Chik66552a82011-03-29 15:59:06 -0700270
Ajay Dudanib01e5062011-12-03 23:23:42 -0800271 for (j = 0; j < 4; j++) {
272 memcpy(&(partition_entries[partition_count].type_guid),
273 &data[(j * partition_entry_size)],
274 PARTITION_TYPE_GUID_SIZE);
275 if (partition_entries[partition_count].type_guid[0] ==
276 0x00
277 && partition_entries[partition_count].
278 type_guid[1] == 0x00) {
279 i = max_partition_count;
280 break;
281 }
282 memcpy(&
283 (partition_entries[partition_count].
284 unique_partition_guid),
285 &data[(j * partition_entry_size) +
286 UNIQUE_GUID_OFFSET],
287 UNIQUE_PARTITION_GUID_SIZE);
288 partition_entries[partition_count].first_lba =
289 GET_LLWORD_FROM_BYTE(&data
290 [(j * partition_entry_size) +
291 FIRST_LBA_OFFSET]);
292 partition_entries[partition_count].last_lba =
293 GET_LLWORD_FROM_BYTE(&data
294 [(j * partition_entry_size) +
295 LAST_LBA_OFFSET]);
296 partition_entries[partition_count].size =
297 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700298 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800299 partition_entries[partition_count].attribute_flag =
300 GET_LLWORD_FROM_BYTE(&data
301 [(j * partition_entry_size) +
302 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700303
Ajay Dudanib01e5062011-12-03 23:23:42 -0800304 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
305 memcpy(UTF16_name, &data[(j * partition_entry_size) +
306 PARTITION_NAME_OFFSET],
307 MAX_GPT_NAME_SIZE);
308 /*
309 * Currently partition names in *.xml are UTF-8 and lowercase
310 * Only supporting english for now so removing 2nd byte of UTF-16
311 */
312 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
313 partition_entries[partition_count].name[n] =
314 UTF16_name[n * 2];
315 }
316 partition_count++;
317 }
318 }
319 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700320}
321
Neeti Desai5f26aff2011-09-30 10:27:40 -0700322static unsigned int write_mbr_in_blocks(unsigned size, unsigned char *mbrImage)
323{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800324 unsigned int dtype;
325 unsigned int dfirstsec;
326 unsigned int ebrSectorOffset;
327 unsigned char *ebrImage;
328 unsigned char *lastAddress;
329 int idx, i;
330 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700331
Ajay Dudanib01e5062011-12-03 23:23:42 -0800332 /* Write the first block */
333 ret = mmc_write(0, BLOCK_SIZE, (unsigned int *)mbrImage);
334 if (ret) {
335 dprintf(CRITICAL, "Failed to write mbr partition\n");
336 goto end;
337 }
338 dprintf(SPEW, "write of first MBR block ok\n");
339 /*
340 Loop through the MBR table to see if there is an EBR.
341 If found, then figure out where to write the first EBR
342 */
343 idx = TABLE_ENTRY_0;
344 for (i = 0; i < 4; i++) {
345 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
346 if (MBR_EBR_TYPE == dtype) {
347 dprintf(SPEW, "EBR found.\n");
348 break;
349 }
350 }
351 if (MBR_EBR_TYPE != dtype) {
352 dprintf(SPEW, "No EBR in this image\n");
353 goto end;
354 }
355 /* EBR exists. Write each EBR block to mmc */
356 ebrImage = mbrImage + BLOCK_SIZE;
357 ebrSectorOffset =
358 GET_LWORD_FROM_BYTE(&mbrImage
359 [idx + i * TABLE_ENTRY_SIZE +
360 OFFSET_FIRST_SEC]);
361 dfirstsec = 0;
362 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
363 lastAddress = mbrImage + size;
364 while (ebrImage < lastAddress) {
365 dprintf(SPEW, "writing to 0x%X\n",
366 (ebrSectorOffset + dfirstsec) * BLOCK_SIZE);
367 ret =
368 mmc_write((ebrSectorOffset + dfirstsec) * BLOCK_SIZE,
369 BLOCK_SIZE, (unsigned int *)ebrImage);
370 if (ret) {
371 dprintf(CRITICAL,
372 "Failed to write EBR block to sector 0x%X\n",
373 dfirstsec);
374 goto end;
375 }
376 dfirstsec =
377 GET_LWORD_FROM_BYTE(&ebrImage
378 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
379 ebrImage += BLOCK_SIZE;
380 }
381 dprintf(INFO, "MBR written to mmc successfully\n");
382 end:
383 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700384}
385
386/* Write the MBR/EBR to the MMC. */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800387unsigned int
388write_mbr(unsigned size, unsigned char *mbrImage,
389 struct mmc_boot_host *mmc_host, struct mmc_boot_card *mmc_card)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700390{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800391 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700392
Ajay Dudanib01e5062011-12-03 23:23:42 -0800393 /* Verify that passed in block is a valid MBR */
394 ret = partition_verify_mbr_signature(size, mbrImage);
395 if (ret) {
396 goto end;
397 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700398
Ajay Dudanib01e5062011-12-03 23:23:42 -0800399 /* Write the MBR/EBR to mmc */
400 ret = write_mbr_in_blocks(size, mbrImage);
401 if (ret) {
402 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
403 goto end;
404 }
405 /* Re-read the MBR partition into mbr table */
406 ret = mmc_boot_read_mbr(mmc_host, mmc_card);
407 if (ret) {
408 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
409 goto end;
410 }
411 partition_dump();
412 end:
413 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700414}
415
416/*
417 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
418*/
419int reflect(int data, int len)
420{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800421 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700422
Ajay Dudanib01e5062011-12-03 23:23:42 -0800423 for (int i = 0; i < len; i++) {
424 if (data & 0x1) {
425 ref |= (1 << ((len - 1) - i));
426 }
427 data = (data >> 1);
428 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700429
Ajay Dudanib01e5062011-12-03 23:23:42 -0800430 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700431}
432
433/*
434* Function to calculate the CRC32
435*/
436unsigned int calculate_crc32(unsigned char *buffer, int len)
437{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800438 int byte_length = 8; /*length of unit (i.e. byte) */
439 int msb = 0;
440 int polynomial = 0x104C11DB7; /* IEEE 32bit polynomial */
441 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
442 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
443 int regs_msb = 0;
444 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700445
Ajay Dudanib01e5062011-12-03 23:23:42 -0800446 for (int i = 0; i < len; i++) {
447 int data_byte = buffer[i];
448 data_byte = reflect(data_byte, 8);
449 for (int j = 0; j < byte_length; j++) {
450 msb = data_byte >> (byte_length - 1); /* get MSB */
451 msb &= 1; /* ensure just 1 bit */
452 regs_msb = (regs >> 31) & 1; /* MSB of regs */
453 regs = regs << 1; /* shift regs for CRC-CCITT */
454 if (regs_msb ^ msb) { /* MSB is a 1 */
455 regs = regs ^ polynomial; /* XOR with generator poly */
456 }
457 regs = regs & regs_mask; /* Mask off excess upper bits */
458 data_byte <<= 1; /* get to next bit */
459 }
460 }
461 regs = regs & regs_mask;
462 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700463
Ajay Dudanib01e5062011-12-03 23:23:42 -0800464 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700465}
466
467/*
468 * Write the GPT Partition Entry Array to the MMC.
469 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800470static unsigned int
471write_gpt_partition_array(unsigned char *header,
472 unsigned int partition_array_start,
473 unsigned int array_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700474{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800475 unsigned int ret = MMC_BOOT_E_INVAL;
476 unsigned long long partition_entry_lba;
477 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700478
Ajay Dudanib01e5062011-12-03 23:23:42 -0800479 partition_entry_lba =
480 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
481 partition_entry_array_start_location = partition_entry_lba * BLOCK_SIZE;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700482
Ajay Dudanib01e5062011-12-03 23:23:42 -0800483 ret = mmc_write(partition_entry_array_start_location, array_size,
484 (unsigned int *)partition_array_start);
485 if (ret) {
486 dprintf(CRITICAL,
487 "GPT: FAILED to write the partition entry array\n");
488 goto end;
489 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700490
Ajay Dudanib01e5062011-12-03 23:23:42 -0800491 end:
492 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700493}
494
Ajay Dudanib01e5062011-12-03 23:23:42 -0800495static void
496patch_gpt(unsigned char *gptImage,
497 struct mmc_boot_card *mmc_card,
498 unsigned int array_size,
499 unsigned int max_part_count, unsigned int part_entry_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700500{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800501 unsigned int partition_entry_array_start;
502 unsigned char *primary_gpt_header;
503 unsigned char *secondary_gpt_header;
504 unsigned int offset;
505 unsigned long long card_size_sec;
506 int total_part = 0;
507 unsigned int last_part_offset;
508 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700509
Ajay Dudanib01e5062011-12-03 23:23:42 -0800510 /* Get size of MMC */
511 card_size_sec = (mmc_card->capacity) / 512;
512 /* Working around cap at 4GB */
513 if (card_size_sec == 0) {
514 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
515 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700516
Ajay Dudanib01e5062011-12-03 23:23:42 -0800517 /* Patching primary header */
518 primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
519 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
520 ((long long)(card_size_sec - 1)));
521 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
522 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700523
Ajay Dudanib01e5062011-12-03 23:23:42 -0800524 /* Patching backup GPT */
525 offset = (2 * array_size);
526 secondary_gpt_header = offset + BLOCK_SIZE + primary_gpt_header;
527 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
528 ((long long)(card_size_sec - 1)));
529 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
530 ((long long)(card_size_sec - 34)));
531 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
532 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700533
Ajay Dudanib01e5062011-12-03 23:23:42 -0800534 /* Find last partition */
535 while (*(primary_gpt_header + BLOCK_SIZE + total_part * ENTRY_SIZE) !=
536 0) {
537 total_part++;
538 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700539
Ajay Dudanib01e5062011-12-03 23:23:42 -0800540 /* Patching last partition */
541 last_part_offset =
542 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
543 PUT_LONG_LONG(primary_gpt_header + BLOCK_SIZE + last_part_offset,
544 (long long)(card_size_sec - 34));
545 PUT_LONG_LONG(primary_gpt_header + BLOCK_SIZE + last_part_offset +
546 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700547
Ajay Dudanib01e5062011-12-03 23:23:42 -0800548 /* Updating CRC of the Partition entry array in both headers */
549 partition_entry_array_start = primary_gpt_header + BLOCK_SIZE;
550 crc_value = calculate_crc32(partition_entry_array_start,
551 max_part_count * part_entry_size);
552 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700553
Ajay Dudanib01e5062011-12-03 23:23:42 -0800554 crc_value = calculate_crc32(partition_entry_array_start + array_size,
555 max_part_count * part_entry_size);
556 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700557
Ajay Dudanib01e5062011-12-03 23:23:42 -0800558 /* Clearing CRC fields to calculate */
559 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
560 crc_value = calculate_crc32(primary_gpt_header, 92);
561 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700562
Ajay Dudanib01e5062011-12-03 23:23:42 -0800563 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
564 crc_value = (calculate_crc32(secondary_gpt_header, 92));
565 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700566
567}
568
569/*
570 * Write the GPT to the MMC.
571 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800572unsigned int
573write_gpt(unsigned size, unsigned char *gptImage,
574 struct mmc_boot_host *mmc_host, struct mmc_boot_card *mmc_card)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700575{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800576 unsigned int ret = MMC_BOOT_E_INVAL;
577 unsigned int header_size;
578 unsigned long long first_usable_lba;
579 unsigned long long backup_header_lba;
580 unsigned int max_partition_count = 0;
581 unsigned int partition_entry_size;
582 unsigned int partition_entry_array_start;
583 unsigned char *primary_gpt_header;
584 unsigned char *secondary_gpt_header;
585 unsigned int offset;
586 unsigned int partition_entry_array_size;
587 unsigned long long primary_header_location; /* address on the emmc card */
588 unsigned long long secondary_header_location; /* address on the emmc card */
Neeti Desai5f26aff2011-09-30 10:27:40 -0700589
Ajay Dudanib01e5062011-12-03 23:23:42 -0800590 /* Verify that passed block has a valid GPT primary header */
591 primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
592 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
593 &partition_entry_size, &header_size,
594 &max_partition_count);
595 if (ret) {
596 dprintf(CRITICAL,
597 "GPT: Primary signature invalid cannot write GPT\n");
598 goto end;
599 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700600
Ajay Dudanib01e5062011-12-03 23:23:42 -0800601 /* Verify that passed block has a valid backup GPT HEADER */
602 partition_entry_array_size = partition_entry_size * max_partition_count;
603 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
604 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
605 }
606 offset = (2 * partition_entry_array_size);
607 secondary_gpt_header = offset + BLOCK_SIZE + primary_gpt_header;
608 ret =
609 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
610 &partition_entry_size, &header_size,
611 &max_partition_count);
612 if (ret) {
613 dprintf(CRITICAL,
614 "GPT: Backup signature invalid cannot write GPT\n");
615 goto end;
616 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700617
Ajay Dudanib01e5062011-12-03 23:23:42 -0800618 /* Patching the primary and the backup header of the GPT table */
619 patch_gpt(gptImage, mmc_card, partition_entry_array_size,
620 max_partition_count, partition_entry_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700621
Ajay Dudanib01e5062011-12-03 23:23:42 -0800622 /* Erasing the eMMC card before writing */
623 ret = mmc_erase_card(0x00000000, mmc_card->capacity);
624 if (ret) {
625 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
626 goto end;
627 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700628
Ajay Dudanib01e5062011-12-03 23:23:42 -0800629 /* Writing protective MBR */
630 ret = mmc_write(0, PROTECTIVE_MBR_SIZE, (unsigned int *)gptImage);
631 if (ret) {
632 dprintf(CRITICAL, "Failed to write Protective MBR\n");
633 goto end;
634 }
635 /* Writing the primary GPT header */
636 primary_header_location = PROTECTIVE_MBR_SIZE;
637 ret = mmc_write(primary_header_location, BLOCK_SIZE,
638 (unsigned int *)primary_gpt_header);
639 if (ret) {
640 dprintf(CRITICAL, "Failed to write GPT header\n");
641 goto end;
642 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700643
Ajay Dudanib01e5062011-12-03 23:23:42 -0800644 /* Writing the backup GPT header */
645 backup_header_lba = GET_LLWORD_FROM_BYTE
646 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
647 secondary_header_location = backup_header_lba * BLOCK_SIZE;
648 ret = mmc_write(secondary_header_location, BLOCK_SIZE,
649 (unsigned int *)secondary_gpt_header);
650 if (ret) {
651 dprintf(CRITICAL, "Failed to write GPT backup header\n");
652 goto end;
653 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700654
Ajay Dudanib01e5062011-12-03 23:23:42 -0800655 /* Writing the partition entries array for the primary header */
656 partition_entry_array_start = primary_gpt_header + BLOCK_SIZE;
657 ret = write_gpt_partition_array(primary_gpt_header,
658 partition_entry_array_start,
659 partition_entry_array_size);
660 if (ret) {
661 dprintf(CRITICAL,
662 "GPT: Could not write GPT Partition entries array\n");
663 goto end;
664 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700665
Ajay Dudanib01e5062011-12-03 23:23:42 -0800666 /*Writing the partition entries array for the backup header */
667 partition_entry_array_start = primary_gpt_header + BLOCK_SIZE +
668 partition_entry_array_size;
669 ret = write_gpt_partition_array(secondary_gpt_header,
670 partition_entry_array_start,
671 partition_entry_array_size);
672 if (ret) {
673 dprintf(CRITICAL,
674 "GPT: Could not write GPT Partition entries array\n");
675 goto end;
676 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700677
Ajay Dudanib01e5062011-12-03 23:23:42 -0800678 /* Re-read the GPT partition table */
679 dprintf(INFO, "Re-reading the GPT Partition Table\n");
680 ret = mmc_boot_read_gpt(mmc_host, mmc_card);
681 if (ret) {
682 dprintf(CRITICAL,
683 "GPT: Failure to re- read the GPT Partition table\n");
684 goto end;
685 }
686 partition_dump();
687 dprintf(CRITICAL, "GPT: Partition Table written\n");
688 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700689
Ajay Dudanib01e5062011-12-03 23:23:42 -0800690 end:
691 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700692}
693
Ajay Dudanib01e5062011-12-03 23:23:42 -0800694unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700695{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800696 unsigned int ret = MMC_BOOT_E_INVAL;
697 unsigned int partition_type;
698 struct mmc_boot_host *mmc_host;
699 struct mmc_boot_card *mmc_card;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700700
Ajay Dudanib01e5062011-12-03 23:23:42 -0800701 if (partition == 0) {
702 dprintf(CRITICAL, "NULL partition\n");
703 goto end;
704 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700705
Ajay Dudanib01e5062011-12-03 23:23:42 -0800706 ret = partition_get_type(size, partition, &partition_type);
707 if (ret != MMC_BOOT_E_SUCCESS) {
708 goto end;
709 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700710
Ajay Dudanib01e5062011-12-03 23:23:42 -0800711 mmc_host = get_mmc_host();
712 mmc_card = get_mmc_card();
Neeti Desai5f26aff2011-09-30 10:27:40 -0700713
Ajay Dudanib01e5062011-12-03 23:23:42 -0800714 switch (partition_type) {
715 case PARTITION_TYPE_MBR:
716 dprintf(INFO, "Writing MBR partition\n");
717 ret = write_mbr(size, partition, mmc_host, mmc_card);
718 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700719
Ajay Dudanib01e5062011-12-03 23:23:42 -0800720 case PARTITION_TYPE_GPT:
721 dprintf(INFO, "Writing GPT partition\n");
722 ret = write_gpt(size, partition, mmc_host, mmc_card);
723 dprintf(CRITICAL, "Re-Flash all the partitions\n");
724 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700725
Ajay Dudanib01e5062011-12-03 23:23:42 -0800726 default:
727 dprintf(CRITICAL, "Invalid partition\n");
728 ret = MMC_BOOT_E_INVAL;
729 goto end;
730 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700731
Ajay Dudanib01e5062011-12-03 23:23:42 -0800732 end:
733 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700734}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800735
Kinson Chikf1a43512011-07-14 11:28:39 -0700736/*
737 * Fill name for android partition found.
738 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800739static void
740mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700741{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800742 switch (type) {
743 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
744 case MBR_MODEM_TYPE:
745 case MBR_MODEM_TYPE2:
746 /* if already assigned last name available then return */
747 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
748 return;
749 strlcpy((char *)partition_ent->name,
750 (const char *)vfat_partitions[vfat_count],
751 sizeof(partition_ent->name));
752 vfat_count++;
753 break;
754 case MBR_SBL1_TYPE:
755 memcpy(partition_ent->name, "sbl1", 4);
756 break;
757 case MBR_SBL2_TYPE:
758 memcpy(partition_ent->name, "sbl2", 4);
759 break;
760 case MBR_SBL3_TYPE:
761 memcpy(partition_ent->name, "sbl3", 4);
762 break;
763 case MBR_RPM_TYPE:
764 memcpy(partition_ent->name, "rpm", 3);
765 break;
766 case MBR_TZ_TYPE:
767 memcpy(partition_ent->name, "tz", 2);
768 break;
769 case MBR_ABOOT_TYPE:
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530770#if PLATFORM_MSM7X27A
771 memcpy(partition_ent->name, "FOTA", 4);
772#else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800773 memcpy(partition_ent->name, "aboot", 5);
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530774#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -0800775 break;
776 case MBR_BOOT_TYPE:
777 memcpy(partition_ent->name, "boot", 4);
778 break;
779 case MBR_MODEM_ST1_TYPE:
780 memcpy(partition_ent->name, "modem_st1", 9);
781 break;
782 case MBR_MODEM_ST2_TYPE:
783 memcpy(partition_ent->name, "modem_st2", 9);
784 break;
785 case MBR_EFS2_TYPE:
786 memcpy(partition_ent->name, "efs2", 4);
787 break;
788 case MBR_USERDATA_TYPE:
789 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
790 return;
791 strlcpy((char *)partition_ent->name,
792 (const char *)ext3_partitions[ext3_count],
793 sizeof(partition_ent->name));
794 ext3_count++;
795 break;
796 case MBR_RECOVERY_TYPE:
797 memcpy(partition_ent->name, "recovery", 8);
798 break;
799 case MBR_MISC_TYPE:
800 memcpy(partition_ent->name, "misc", 4);
801 break;
Neeti Desai2d6b0e42012-03-23 15:48:57 -0700802 case MBR_SSD_TYPE:
803 memcpy(partition_ent->name, "ssd", 3);
804 break;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800805 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700806}
807
808/*
809 * Find index of parition in array of partition entries
810 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800811unsigned partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700812{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800813 unsigned int input_string_length = strlen(name);
814 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700815
neetid6c38de12011-12-02 12:04:50 -0800816 if( partition_count >= NUM_PARTITIONS)
817 {
818 return INVALID_PTN;
819 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800820 for (n = 0; n < partition_count; n++) {
821 if (!memcmp
822 (name, &partition_entries[n].name, input_string_length)
823 && input_string_length ==
824 strlen((const char *)&partition_entries[n].name)) {
825 return n;
826 }
827 }
828 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700829}
830
831/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800832unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700833{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800834 if (index == INVALID_PTN)
835 return 0;
836 else {
837 return partition_entries[index].size * BLOCK_SIZE;
838 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700839}
840
841/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800842unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700843{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800844 if (index == INVALID_PTN)
845 return 0;
846 else {
847 return partition_entries[index].first_lba * BLOCK_SIZE;
848 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700849}
850
851/* Debug: Print all parsed partitions */
852void partition_dump()
853{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800854 unsigned i = 0;
855 for (i = 0; i < partition_count; i++) {
856 dprintf(SPEW,
857 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
858 i, partition_entries[i].name, partition_entries[i].size,
859 partition_entries[i].dtype,
860 partition_entries[i].first_lba,
861 partition_entries[i].last_lba);
862 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700863}
864
Ajay Dudanib01e5062011-12-03 23:23:42 -0800865unsigned int
866partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700867{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800868 /* Avoid checking past end of buffer */
869 if ((TABLE_SIGNATURE + 1) > size) {
870 return MMC_BOOT_E_FAILURE;
871 }
872 /* Check to see if signature exists */
873 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
874 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
875 dprintf(CRITICAL, "MBR signature does not match.\n");
876 return MMC_BOOT_E_FAILURE;
877 }
878 return MMC_BOOT_E_SUCCESS;
Kinson Chikf1a43512011-07-14 11:28:39 -0700879}
880
Ajay Dudanib01e5062011-12-03 23:23:42 -0800881unsigned int
882mbr_partition_get_type(unsigned size, unsigned char *partition,
883 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700884{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800885 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700886
Ajay Dudanib01e5062011-12-03 23:23:42 -0800887 if (size < type_offset) {
888 goto end;
889 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700890
Ajay Dudanib01e5062011-12-03 23:23:42 -0800891 *partition_type = partition[type_offset];
892 end:
893 return MMC_BOOT_E_SUCCESS;
Kinson Chikf1a43512011-07-14 11:28:39 -0700894}
895
Ajay Dudanib01e5062011-12-03 23:23:42 -0800896unsigned int
897partition_get_type(unsigned size, unsigned char *partition,
898 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700899{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800900 unsigned int ret = MMC_BOOT_E_SUCCESS;
Kinson Chikf1a43512011-07-14 11:28:39 -0700901
Ajay Dudanib01e5062011-12-03 23:23:42 -0800902 /*
903 * If the block contains the MBR signature, then it's likely either
904 * MBR or MBR with protective type (GPT). If the MBR signature is
905 * not there, then it could be the GPT backup.
906 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700907
Ajay Dudanib01e5062011-12-03 23:23:42 -0800908 /* First check the MBR signature */
909 ret = partition_verify_mbr_signature(size, partition);
910 if (ret == MMC_BOOT_E_SUCCESS) {
911 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -0700912
Ajay Dudanib01e5062011-12-03 23:23:42 -0800913 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
914 ret =
915 mbr_partition_get_type(size, partition,
916 &mbr_partition_type);
917 if (ret != MMC_BOOT_E_SUCCESS) {
918 dprintf(CRITICAL, "Cannot get TYPE of partition");
919 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
920 *partition_type = PARTITION_TYPE_GPT;
921 } else {
922 *partition_type = PARTITION_TYPE_MBR;
923 }
924 } else {
925 /*
926 * This could be the GPT backup. Make that assumption for now.
927 * Anybody who treats the block as GPT backup should check the
928 * signature.
929 */
930 *partition_type = PARTITION_TYPE_GPT_BACKUP;
931 }
932 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700933}
Kinson Chik4d7444f2011-09-13 15:48:51 -0700934
935/*
936 * Parse the gpt header and get the required header fields
937 * Return 0 on valid signature
938 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800939unsigned int
940partition_parse_gpt_header(unsigned char *buffer,
941 unsigned long long *first_usable_lba,
942 unsigned int *partition_entry_size,
943 unsigned int *header_size,
944 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -0700945{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800946 /* Check GPT Signature */
947 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
948 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
949 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -0700950
Ajay Dudanib01e5062011-12-03 23:23:42 -0800951 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
952 *first_usable_lba =
953 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
954 *max_partition_count =
955 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
956 *partition_entry_size =
957 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700958
Ajay Dudanib01e5062011-12-03 23:23:42 -0800959 return 0;
Kinson Chik4d7444f2011-09-13 15:48:51 -0700960}