blob: 0b1bf4685d9e9c2f9caa9e3fa640eb3140d361a2 [file] [log] [blame]
Kinson Chik66552a82011-03-29 15:59:06 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2
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;
202 unsigned int max_partition_count = 0;
203 unsigned int partition_entry_size;
204 unsigned char data[BLOCK_SIZE];
205 unsigned int i = 0; /* Counter for each 512 block */
206 unsigned int j = 0; /* Counter for each 128 entry in the 512 block */
207 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
208 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
209 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
210 unsigned long long partition_0 = 2;
211 partition_count = 0;
Kinson Chik66552a82011-03-29 15:59:06 -0700212
Ajay Dudanib01e5062011-12-03 23:23:42 -0800213 /* Print out the GPT first */
214 ret = mmc_boot_read_from_card(mmc_host, mmc_card,
215 PROTECTIVE_MBR_SIZE,
216 BLOCK_SIZE, (unsigned int *)data);
217 if (ret)
218 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Kinson Chik66552a82011-03-29 15:59:06 -0700219
Ajay Dudanib01e5062011-12-03 23:23:42 -0800220 ret = partition_parse_gpt_header(data, &first_usable_lba,
221 &partition_entry_size, &header_size,
222 &max_partition_count);
223 if (ret) {
224 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700225
Ajay Dudanib01e5062011-12-03 23:23:42 -0800226 /* Check the backup gpt */
227 backup_header_lba =
228 GET_LLWORD_FROM_BYTE(&data[BACKUP_HEADER_OFFSET]);
229 ret =
230 mmc_boot_read_from_card(mmc_host, mmc_card,
231 (backup_header_lba * BLOCK_SIZE),
232 BLOCK_SIZE, (unsigned int *)data);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700233
Ajay Dudanib01e5062011-12-03 23:23:42 -0800234 if (ret) {
235 dprintf(CRITICAL,
236 "GPT: Could not read backup gpt from mmc\n");
237 return ret;
238 }
Kinson Chik4d7444f2011-09-13 15:48:51 -0700239
Ajay Dudanib01e5062011-12-03 23:23:42 -0800240 ret = partition_parse_gpt_header(data, &first_usable_lba,
241 &partition_entry_size,
242 &header_size,
243 &max_partition_count);
244 if (ret) {
245 dprintf(CRITICAL,
246 "GPT: Primary and backup signatures invalid\n");
247 return ret;
248 }
249 partition_0 = backup_header_lba - (max_partition_count / 4);
250 }
Kinson Chik66552a82011-03-29 15:59:06 -0700251
Ajay Dudanib01e5062011-12-03 23:23:42 -0800252 /* Read GPT Entries */
253 for (i = 0; i < (max_partition_count / 4); i++) {
neetid6c38de12011-12-02 12:04:50 -0800254 ASSERT(partition_count < NUM_PARTITIONS);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800255 ret = mmc_boot_read_from_card(mmc_host, mmc_card,
256 (partition_0 * BLOCK_SIZE) +
257 (i * BLOCK_SIZE),
258 BLOCK_SIZE, (uint32_t *) data);
Kinson Chik66552a82011-03-29 15:59:06 -0700259
Ajay Dudanib01e5062011-12-03 23:23:42 -0800260 if (ret) {
261 dprintf(CRITICAL,
262 "GPT: mmc read card failed reading partition entries.\n");
263 return ret;
264 }
Kinson Chik66552a82011-03-29 15:59:06 -0700265
Ajay Dudanib01e5062011-12-03 23:23:42 -0800266 for (j = 0; j < 4; j++) {
267 memcpy(&(partition_entries[partition_count].type_guid),
268 &data[(j * partition_entry_size)],
269 PARTITION_TYPE_GUID_SIZE);
270 if (partition_entries[partition_count].type_guid[0] ==
271 0x00
272 && partition_entries[partition_count].
273 type_guid[1] == 0x00) {
274 i = max_partition_count;
275 break;
276 }
277 memcpy(&
278 (partition_entries[partition_count].
279 unique_partition_guid),
280 &data[(j * partition_entry_size) +
281 UNIQUE_GUID_OFFSET],
282 UNIQUE_PARTITION_GUID_SIZE);
283 partition_entries[partition_count].first_lba =
284 GET_LLWORD_FROM_BYTE(&data
285 [(j * partition_entry_size) +
286 FIRST_LBA_OFFSET]);
287 partition_entries[partition_count].last_lba =
288 GET_LLWORD_FROM_BYTE(&data
289 [(j * partition_entry_size) +
290 LAST_LBA_OFFSET]);
291 partition_entries[partition_count].size =
292 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700293 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800294 partition_entries[partition_count].attribute_flag =
295 GET_LLWORD_FROM_BYTE(&data
296 [(j * partition_entry_size) +
297 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700298
Ajay Dudanib01e5062011-12-03 23:23:42 -0800299 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
300 memcpy(UTF16_name, &data[(j * partition_entry_size) +
301 PARTITION_NAME_OFFSET],
302 MAX_GPT_NAME_SIZE);
303 /*
304 * Currently partition names in *.xml are UTF-8 and lowercase
305 * Only supporting english for now so removing 2nd byte of UTF-16
306 */
307 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
308 partition_entries[partition_count].name[n] =
309 UTF16_name[n * 2];
310 }
311 partition_count++;
312 }
313 }
314 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700315}
316
Neeti Desai5f26aff2011-09-30 10:27:40 -0700317static unsigned int write_mbr_in_blocks(unsigned size, unsigned char *mbrImage)
318{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800319 unsigned int dtype;
320 unsigned int dfirstsec;
321 unsigned int ebrSectorOffset;
322 unsigned char *ebrImage;
323 unsigned char *lastAddress;
324 int idx, i;
325 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700326
Ajay Dudanib01e5062011-12-03 23:23:42 -0800327 /* Write the first block */
328 ret = mmc_write(0, BLOCK_SIZE, (unsigned int *)mbrImage);
329 if (ret) {
330 dprintf(CRITICAL, "Failed to write mbr partition\n");
331 goto end;
332 }
333 dprintf(SPEW, "write of first MBR block ok\n");
334 /*
335 Loop through the MBR table to see if there is an EBR.
336 If found, then figure out where to write the first EBR
337 */
338 idx = TABLE_ENTRY_0;
339 for (i = 0; i < 4; i++) {
340 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
341 if (MBR_EBR_TYPE == dtype) {
342 dprintf(SPEW, "EBR found.\n");
343 break;
344 }
345 }
346 if (MBR_EBR_TYPE != dtype) {
347 dprintf(SPEW, "No EBR in this image\n");
348 goto end;
349 }
350 /* EBR exists. Write each EBR block to mmc */
351 ebrImage = mbrImage + BLOCK_SIZE;
352 ebrSectorOffset =
353 GET_LWORD_FROM_BYTE(&mbrImage
354 [idx + i * TABLE_ENTRY_SIZE +
355 OFFSET_FIRST_SEC]);
356 dfirstsec = 0;
357 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
358 lastAddress = mbrImage + size;
359 while (ebrImage < lastAddress) {
360 dprintf(SPEW, "writing to 0x%X\n",
361 (ebrSectorOffset + dfirstsec) * BLOCK_SIZE);
362 ret =
363 mmc_write((ebrSectorOffset + dfirstsec) * BLOCK_SIZE,
364 BLOCK_SIZE, (unsigned int *)ebrImage);
365 if (ret) {
366 dprintf(CRITICAL,
367 "Failed to write EBR block to sector 0x%X\n",
368 dfirstsec);
369 goto end;
370 }
371 dfirstsec =
372 GET_LWORD_FROM_BYTE(&ebrImage
373 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
374 ebrImage += BLOCK_SIZE;
375 }
376 dprintf(INFO, "MBR written to mmc successfully\n");
377 end:
378 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700379}
380
381/* Write the MBR/EBR to the MMC. */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800382unsigned int
383write_mbr(unsigned size, unsigned char *mbrImage,
384 struct mmc_boot_host *mmc_host, struct mmc_boot_card *mmc_card)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700385{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800386 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700387
Ajay Dudanib01e5062011-12-03 23:23:42 -0800388 /* Verify that passed in block is a valid MBR */
389 ret = partition_verify_mbr_signature(size, mbrImage);
390 if (ret) {
391 goto end;
392 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700393
Ajay Dudanib01e5062011-12-03 23:23:42 -0800394 /* Write the MBR/EBR to mmc */
395 ret = write_mbr_in_blocks(size, mbrImage);
396 if (ret) {
397 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
398 goto end;
399 }
400 /* Re-read the MBR partition into mbr table */
401 ret = mmc_boot_read_mbr(mmc_host, mmc_card);
402 if (ret) {
403 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
404 goto end;
405 }
406 partition_dump();
407 end:
408 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700409}
410
411/*
412 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
413*/
414int reflect(int data, int len)
415{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800416 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700417
Ajay Dudanib01e5062011-12-03 23:23:42 -0800418 for (int i = 0; i < len; i++) {
419 if (data & 0x1) {
420 ref |= (1 << ((len - 1) - i));
421 }
422 data = (data >> 1);
423 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700424
Ajay Dudanib01e5062011-12-03 23:23:42 -0800425 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700426}
427
428/*
429* Function to calculate the CRC32
430*/
431unsigned int calculate_crc32(unsigned char *buffer, int len)
432{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800433 int byte_length = 8; /*length of unit (i.e. byte) */
434 int msb = 0;
435 int polynomial = 0x104C11DB7; /* IEEE 32bit polynomial */
436 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
437 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
438 int regs_msb = 0;
439 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700440
Ajay Dudanib01e5062011-12-03 23:23:42 -0800441 for (int i = 0; i < len; i++) {
442 int data_byte = buffer[i];
443 data_byte = reflect(data_byte, 8);
444 for (int j = 0; j < byte_length; j++) {
445 msb = data_byte >> (byte_length - 1); /* get MSB */
446 msb &= 1; /* ensure just 1 bit */
447 regs_msb = (regs >> 31) & 1; /* MSB of regs */
448 regs = regs << 1; /* shift regs for CRC-CCITT */
449 if (regs_msb ^ msb) { /* MSB is a 1 */
450 regs = regs ^ polynomial; /* XOR with generator poly */
451 }
452 regs = regs & regs_mask; /* Mask off excess upper bits */
453 data_byte <<= 1; /* get to next bit */
454 }
455 }
456 regs = regs & regs_mask;
457 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700458
Ajay Dudanib01e5062011-12-03 23:23:42 -0800459 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700460}
461
462/*
463 * Write the GPT Partition Entry Array to the MMC.
464 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800465static unsigned int
466write_gpt_partition_array(unsigned char *header,
467 unsigned int partition_array_start,
468 unsigned int array_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700469{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800470 unsigned int ret = MMC_BOOT_E_INVAL;
471 unsigned long long partition_entry_lba;
472 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700473
Ajay Dudanib01e5062011-12-03 23:23:42 -0800474 partition_entry_lba =
475 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
476 partition_entry_array_start_location = partition_entry_lba * BLOCK_SIZE;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700477
Ajay Dudanib01e5062011-12-03 23:23:42 -0800478 ret = mmc_write(partition_entry_array_start_location, array_size,
479 (unsigned int *)partition_array_start);
480 if (ret) {
481 dprintf(CRITICAL,
482 "GPT: FAILED to write the partition entry array\n");
483 goto end;
484 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700485
Ajay Dudanib01e5062011-12-03 23:23:42 -0800486 end:
487 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700488}
489
Ajay Dudanib01e5062011-12-03 23:23:42 -0800490static void
491patch_gpt(unsigned char *gptImage,
492 struct mmc_boot_card *mmc_card,
493 unsigned int array_size,
494 unsigned int max_part_count, unsigned int part_entry_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700495{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800496 unsigned int partition_entry_array_start;
497 unsigned char *primary_gpt_header;
498 unsigned char *secondary_gpt_header;
499 unsigned int offset;
500 unsigned long long card_size_sec;
501 int total_part = 0;
502 unsigned int last_part_offset;
503 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700504
Ajay Dudanib01e5062011-12-03 23:23:42 -0800505 /* Get size of MMC */
506 card_size_sec = (mmc_card->capacity) / 512;
507 /* Working around cap at 4GB */
508 if (card_size_sec == 0) {
509 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
510 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700511
Ajay Dudanib01e5062011-12-03 23:23:42 -0800512 /* Patching primary header */
513 primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
514 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
515 ((long long)(card_size_sec - 1)));
516 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
517 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700518
Ajay Dudanib01e5062011-12-03 23:23:42 -0800519 /* Patching backup GPT */
520 offset = (2 * array_size);
521 secondary_gpt_header = offset + BLOCK_SIZE + primary_gpt_header;
522 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
523 ((long long)(card_size_sec - 1)));
524 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
525 ((long long)(card_size_sec - 34)));
526 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
527 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700528
Ajay Dudanib01e5062011-12-03 23:23:42 -0800529 /* Find last partition */
530 while (*(primary_gpt_header + BLOCK_SIZE + total_part * ENTRY_SIZE) !=
531 0) {
532 total_part++;
533 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700534
Ajay Dudanib01e5062011-12-03 23:23:42 -0800535 /* Patching last partition */
536 last_part_offset =
537 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
538 PUT_LONG_LONG(primary_gpt_header + BLOCK_SIZE + last_part_offset,
539 (long long)(card_size_sec - 34));
540 PUT_LONG_LONG(primary_gpt_header + BLOCK_SIZE + last_part_offset +
541 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700542
Ajay Dudanib01e5062011-12-03 23:23:42 -0800543 /* Updating CRC of the Partition entry array in both headers */
544 partition_entry_array_start = primary_gpt_header + BLOCK_SIZE;
545 crc_value = calculate_crc32(partition_entry_array_start,
546 max_part_count * part_entry_size);
547 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700548
Ajay Dudanib01e5062011-12-03 23:23:42 -0800549 crc_value = calculate_crc32(partition_entry_array_start + array_size,
550 max_part_count * part_entry_size);
551 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700552
Ajay Dudanib01e5062011-12-03 23:23:42 -0800553 /* Clearing CRC fields to calculate */
554 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
555 crc_value = calculate_crc32(primary_gpt_header, 92);
556 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700557
Ajay Dudanib01e5062011-12-03 23:23:42 -0800558 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
559 crc_value = (calculate_crc32(secondary_gpt_header, 92));
560 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700561
562}
563
564/*
565 * Write the GPT to the MMC.
566 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800567unsigned int
568write_gpt(unsigned size, unsigned char *gptImage,
569 struct mmc_boot_host *mmc_host, struct mmc_boot_card *mmc_card)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700570{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800571 unsigned int ret = MMC_BOOT_E_INVAL;
572 unsigned int header_size;
573 unsigned long long first_usable_lba;
574 unsigned long long backup_header_lba;
575 unsigned int max_partition_count = 0;
576 unsigned int partition_entry_size;
577 unsigned int partition_entry_array_start;
578 unsigned char *primary_gpt_header;
579 unsigned char *secondary_gpt_header;
580 unsigned int offset;
581 unsigned int partition_entry_array_size;
582 unsigned long long primary_header_location; /* address on the emmc card */
583 unsigned long long secondary_header_location; /* address on the emmc card */
Neeti Desai5f26aff2011-09-30 10:27:40 -0700584
Ajay Dudanib01e5062011-12-03 23:23:42 -0800585 /* Verify that passed block has a valid GPT primary header */
586 primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
587 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
588 &partition_entry_size, &header_size,
589 &max_partition_count);
590 if (ret) {
591 dprintf(CRITICAL,
592 "GPT: Primary signature invalid cannot write GPT\n");
593 goto end;
594 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700595
Ajay Dudanib01e5062011-12-03 23:23:42 -0800596 /* Verify that passed block has a valid backup GPT HEADER */
597 partition_entry_array_size = partition_entry_size * max_partition_count;
598 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
599 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
600 }
601 offset = (2 * partition_entry_array_size);
602 secondary_gpt_header = offset + BLOCK_SIZE + primary_gpt_header;
603 ret =
604 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
605 &partition_entry_size, &header_size,
606 &max_partition_count);
607 if (ret) {
608 dprintf(CRITICAL,
609 "GPT: Backup signature invalid cannot write GPT\n");
610 goto end;
611 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700612
Ajay Dudanib01e5062011-12-03 23:23:42 -0800613 /* Patching the primary and the backup header of the GPT table */
614 patch_gpt(gptImage, mmc_card, partition_entry_array_size,
615 max_partition_count, partition_entry_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700616
Ajay Dudanib01e5062011-12-03 23:23:42 -0800617 /* Erasing the eMMC card before writing */
618 ret = mmc_erase_card(0x00000000, mmc_card->capacity);
619 if (ret) {
620 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
621 goto end;
622 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700623
Ajay Dudanib01e5062011-12-03 23:23:42 -0800624 /* Writing protective MBR */
625 ret = mmc_write(0, PROTECTIVE_MBR_SIZE, (unsigned int *)gptImage);
626 if (ret) {
627 dprintf(CRITICAL, "Failed to write Protective MBR\n");
628 goto end;
629 }
630 /* Writing the primary GPT header */
631 primary_header_location = PROTECTIVE_MBR_SIZE;
632 ret = mmc_write(primary_header_location, BLOCK_SIZE,
633 (unsigned int *)primary_gpt_header);
634 if (ret) {
635 dprintf(CRITICAL, "Failed to write GPT header\n");
636 goto end;
637 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700638
Ajay Dudanib01e5062011-12-03 23:23:42 -0800639 /* Writing the backup GPT header */
640 backup_header_lba = GET_LLWORD_FROM_BYTE
641 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
642 secondary_header_location = backup_header_lba * BLOCK_SIZE;
643 ret = mmc_write(secondary_header_location, BLOCK_SIZE,
644 (unsigned int *)secondary_gpt_header);
645 if (ret) {
646 dprintf(CRITICAL, "Failed to write GPT backup header\n");
647 goto end;
648 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700649
Ajay Dudanib01e5062011-12-03 23:23:42 -0800650 /* Writing the partition entries array for the primary header */
651 partition_entry_array_start = primary_gpt_header + BLOCK_SIZE;
652 ret = write_gpt_partition_array(primary_gpt_header,
653 partition_entry_array_start,
654 partition_entry_array_size);
655 if (ret) {
656 dprintf(CRITICAL,
657 "GPT: Could not write GPT Partition entries array\n");
658 goto end;
659 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700660
Ajay Dudanib01e5062011-12-03 23:23:42 -0800661 /*Writing the partition entries array for the backup header */
662 partition_entry_array_start = primary_gpt_header + BLOCK_SIZE +
663 partition_entry_array_size;
664 ret = write_gpt_partition_array(secondary_gpt_header,
665 partition_entry_array_start,
666 partition_entry_array_size);
667 if (ret) {
668 dprintf(CRITICAL,
669 "GPT: Could not write GPT Partition entries array\n");
670 goto end;
671 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700672
Ajay Dudanib01e5062011-12-03 23:23:42 -0800673 /* Re-read the GPT partition table */
674 dprintf(INFO, "Re-reading the GPT Partition Table\n");
675 ret = mmc_boot_read_gpt(mmc_host, mmc_card);
676 if (ret) {
677 dprintf(CRITICAL,
678 "GPT: Failure to re- read the GPT Partition table\n");
679 goto end;
680 }
681 partition_dump();
682 dprintf(CRITICAL, "GPT: Partition Table written\n");
683 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700684
Ajay Dudanib01e5062011-12-03 23:23:42 -0800685 end:
686 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700687}
688
Ajay Dudanib01e5062011-12-03 23:23:42 -0800689unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700690{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800691 unsigned int ret = MMC_BOOT_E_INVAL;
692 unsigned int partition_type;
693 struct mmc_boot_host *mmc_host;
694 struct mmc_boot_card *mmc_card;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700695
Ajay Dudanib01e5062011-12-03 23:23:42 -0800696 if (partition == 0) {
697 dprintf(CRITICAL, "NULL partition\n");
698 goto end;
699 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700700
Ajay Dudanib01e5062011-12-03 23:23:42 -0800701 ret = partition_get_type(size, partition, &partition_type);
702 if (ret != MMC_BOOT_E_SUCCESS) {
703 goto end;
704 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700705
Ajay Dudanib01e5062011-12-03 23:23:42 -0800706 mmc_host = get_mmc_host();
707 mmc_card = get_mmc_card();
Neeti Desai5f26aff2011-09-30 10:27:40 -0700708
Ajay Dudanib01e5062011-12-03 23:23:42 -0800709 switch (partition_type) {
710 case PARTITION_TYPE_MBR:
711 dprintf(INFO, "Writing MBR partition\n");
712 ret = write_mbr(size, partition, mmc_host, mmc_card);
713 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700714
Ajay Dudanib01e5062011-12-03 23:23:42 -0800715 case PARTITION_TYPE_GPT:
716 dprintf(INFO, "Writing GPT partition\n");
717 ret = write_gpt(size, partition, mmc_host, mmc_card);
718 dprintf(CRITICAL, "Re-Flash all the partitions\n");
719 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700720
Ajay Dudanib01e5062011-12-03 23:23:42 -0800721 default:
722 dprintf(CRITICAL, "Invalid partition\n");
723 ret = MMC_BOOT_E_INVAL;
724 goto end;
725 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700726
Ajay Dudanib01e5062011-12-03 23:23:42 -0800727 end:
728 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700729}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800730
Kinson Chikf1a43512011-07-14 11:28:39 -0700731/*
732 * Fill name for android partition found.
733 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800734static void
735mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700736{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800737 switch (type) {
738 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
739 case MBR_MODEM_TYPE:
740 case MBR_MODEM_TYPE2:
741 /* if already assigned last name available then return */
742 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
743 return;
744 strlcpy((char *)partition_ent->name,
745 (const char *)vfat_partitions[vfat_count],
746 sizeof(partition_ent->name));
747 vfat_count++;
748 break;
749 case MBR_SBL1_TYPE:
750 memcpy(partition_ent->name, "sbl1", 4);
751 break;
752 case MBR_SBL2_TYPE:
753 memcpy(partition_ent->name, "sbl2", 4);
754 break;
755 case MBR_SBL3_TYPE:
756 memcpy(partition_ent->name, "sbl3", 4);
757 break;
758 case MBR_RPM_TYPE:
759 memcpy(partition_ent->name, "rpm", 3);
760 break;
761 case MBR_TZ_TYPE:
762 memcpy(partition_ent->name, "tz", 2);
763 break;
764 case MBR_ABOOT_TYPE:
765 memcpy(partition_ent->name, "aboot", 5);
766 break;
767 case MBR_BOOT_TYPE:
768 memcpy(partition_ent->name, "boot", 4);
769 break;
770 case MBR_MODEM_ST1_TYPE:
771 memcpy(partition_ent->name, "modem_st1", 9);
772 break;
773 case MBR_MODEM_ST2_TYPE:
774 memcpy(partition_ent->name, "modem_st2", 9);
775 break;
776 case MBR_EFS2_TYPE:
777 memcpy(partition_ent->name, "efs2", 4);
778 break;
779 case MBR_USERDATA_TYPE:
780 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
781 return;
782 strlcpy((char *)partition_ent->name,
783 (const char *)ext3_partitions[ext3_count],
784 sizeof(partition_ent->name));
785 ext3_count++;
786 break;
787 case MBR_RECOVERY_TYPE:
788 memcpy(partition_ent->name, "recovery", 8);
789 break;
790 case MBR_MISC_TYPE:
791 memcpy(partition_ent->name, "misc", 4);
792 break;
793 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700794}
795
796/*
797 * Find index of parition in array of partition entries
798 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800799unsigned partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700800{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800801 unsigned int input_string_length = strlen(name);
802 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700803
neetid6c38de12011-12-02 12:04:50 -0800804 if( partition_count >= NUM_PARTITIONS)
805 {
806 return INVALID_PTN;
807 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800808 for (n = 0; n < partition_count; n++) {
809 if (!memcmp
810 (name, &partition_entries[n].name, input_string_length)
811 && input_string_length ==
812 strlen((const char *)&partition_entries[n].name)) {
813 return n;
814 }
815 }
816 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700817}
818
819/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800820unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700821{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800822 if (index == INVALID_PTN)
823 return 0;
824 else {
825 return partition_entries[index].size * BLOCK_SIZE;
826 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700827}
828
829/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800830unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700831{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800832 if (index == INVALID_PTN)
833 return 0;
834 else {
835 return partition_entries[index].first_lba * BLOCK_SIZE;
836 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700837}
838
839/* Debug: Print all parsed partitions */
840void partition_dump()
841{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800842 unsigned i = 0;
843 for (i = 0; i < partition_count; i++) {
844 dprintf(SPEW,
845 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
846 i, partition_entries[i].name, partition_entries[i].size,
847 partition_entries[i].dtype,
848 partition_entries[i].first_lba,
849 partition_entries[i].last_lba);
850 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700851}
852
Ajay Dudanib01e5062011-12-03 23:23:42 -0800853unsigned int
854partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700855{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800856 /* Avoid checking past end of buffer */
857 if ((TABLE_SIGNATURE + 1) > size) {
858 return MMC_BOOT_E_FAILURE;
859 }
860 /* Check to see if signature exists */
861 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
862 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
863 dprintf(CRITICAL, "MBR signature does not match.\n");
864 return MMC_BOOT_E_FAILURE;
865 }
866 return MMC_BOOT_E_SUCCESS;
Kinson Chikf1a43512011-07-14 11:28:39 -0700867}
868
Ajay Dudanib01e5062011-12-03 23:23:42 -0800869unsigned int
870mbr_partition_get_type(unsigned size, unsigned char *partition,
871 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700872{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800873 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700874
Ajay Dudanib01e5062011-12-03 23:23:42 -0800875 if (size < type_offset) {
876 goto end;
877 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700878
Ajay Dudanib01e5062011-12-03 23:23:42 -0800879 *partition_type = partition[type_offset];
880 end:
881 return MMC_BOOT_E_SUCCESS;
Kinson Chikf1a43512011-07-14 11:28:39 -0700882}
883
Ajay Dudanib01e5062011-12-03 23:23:42 -0800884unsigned int
885partition_get_type(unsigned size, unsigned char *partition,
886 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700887{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800888 unsigned int ret = MMC_BOOT_E_SUCCESS;
Kinson Chikf1a43512011-07-14 11:28:39 -0700889
Ajay Dudanib01e5062011-12-03 23:23:42 -0800890 /*
891 * If the block contains the MBR signature, then it's likely either
892 * MBR or MBR with protective type (GPT). If the MBR signature is
893 * not there, then it could be the GPT backup.
894 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700895
Ajay Dudanib01e5062011-12-03 23:23:42 -0800896 /* First check the MBR signature */
897 ret = partition_verify_mbr_signature(size, partition);
898 if (ret == MMC_BOOT_E_SUCCESS) {
899 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -0700900
Ajay Dudanib01e5062011-12-03 23:23:42 -0800901 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
902 ret =
903 mbr_partition_get_type(size, partition,
904 &mbr_partition_type);
905 if (ret != MMC_BOOT_E_SUCCESS) {
906 dprintf(CRITICAL, "Cannot get TYPE of partition");
907 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
908 *partition_type = PARTITION_TYPE_GPT;
909 } else {
910 *partition_type = PARTITION_TYPE_MBR;
911 }
912 } else {
913 /*
914 * This could be the GPT backup. Make that assumption for now.
915 * Anybody who treats the block as GPT backup should check the
916 * signature.
917 */
918 *partition_type = PARTITION_TYPE_GPT_BACKUP;
919 }
920 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700921}
Kinson Chik4d7444f2011-09-13 15:48:51 -0700922
923/*
924 * Parse the gpt header and get the required header fields
925 * Return 0 on valid signature
926 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800927unsigned int
928partition_parse_gpt_header(unsigned char *buffer,
929 unsigned long long *first_usable_lba,
930 unsigned int *partition_entry_size,
931 unsigned int *header_size,
932 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -0700933{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800934 /* Check GPT Signature */
935 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
936 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
937 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -0700938
Ajay Dudanib01e5062011-12-03 23:23:42 -0800939 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
940 *first_usable_lba =
941 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
942 *max_partition_count =
943 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
944 *partition_entry_size =
945 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700946
Ajay Dudanib01e5062011-12-03 23:23:42 -0800947 return 0;
Kinson Chik4d7444f2011-09-13 15:48:51 -0700948}