blob: 621aa907455410ec542100534826acecb305e543 [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
Kinson Chikf1a43512011-07-14 11:28:39 -070034char *ext3_partitions[] = {"system", "userdata", "persist", "cache", "tombstones"};
35char *vfat_partitions[] = {"modem", "mdm", "NONE"};
36unsigned int ext3_count = 0;
37unsigned int vfat_count = 0;
38
39struct partition_entry partition_entries[NUM_PARTITIONS];
40unsigned gpt_partitions_exist = 0;
41unsigned partition_count = 0;
42
43//TODO: Remove the dependency of mmc in these functions
44unsigned int partition_read_table( struct mmc_boot_host * mmc_host,
45 struct mmc_boot_card * mmc_card)
46{
47 unsigned int ret;
48
49 /* Read MBR of the card */
50 ret = mmc_boot_read_mbr( mmc_host, mmc_card );
51 if( ret != MMC_BOOT_E_SUCCESS )
52 {
53 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n" );
54 return MMC_BOOT_E_FAILURE;
55 }
56
57 /* Read GPT of the card if exist */
58 if(gpt_partitions_exist){
59 ret = mmc_boot_read_gpt(mmc_host, mmc_card);
60 if( ret != MMC_BOOT_E_SUCCESS )
61 {
62 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n" );
63 return MMC_BOOT_E_FAILURE;
64 }
65 }
66 return MMC_BOOT_E_SUCCESS;
67}
68
69/*
70 * Read MBR from MMC card and fill partition table.
71 */
72unsigned int mmc_boot_read_mbr( struct mmc_boot_host * mmc_host,
73 struct mmc_boot_card * mmc_card)
74{
75 unsigned char buffer[MMC_BOOT_RD_BLOCK_LEN];
76 unsigned int dtype;
77 unsigned int dfirstsec;
78 unsigned int EBR_first_sec;
79 unsigned int EBR_current_sec;
80 int ret = MMC_BOOT_E_SUCCESS;
81 int idx, i;
82
83 /* Print out the MBR first */
84 ret = mmc_boot_read_from_card( mmc_host, mmc_card, 0, \
85 MMC_BOOT_RD_BLOCK_LEN, \
86 (unsigned int *)buffer);
87 if (ret)
88 {
89 dprintf(CRITICAL, "Could not read partition from mmc");
90 return ret;
91 }
92
93 /* Check to see if signature exists */
94 ret = partition_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, buffer);
95 if (ret)
96 {
97 return ret;
98 }
99
100 /*
101 * Process each of the four partitions in the MBR by reading the table
102 * information into our mbr table.
103 */
104 partition_count = 0;
105 idx = TABLE_ENTRY_0;
106 for (i = 0; i < 4; i++)
107 {
108 /* Type 0xEE indicates end of MBR and GPT partitions exist */
109 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
110 if (dtype == MBR_PROTECTED_TYPE){
111 gpt_partitions_exist = 1;
112 return ret;
113 }
114 partition_entries[partition_count].dtype = dtype;
115 partition_entries[partition_count].attribute_flag = \
116 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
117 partition_entries[partition_count].first_lba = \
118 GET_LWORD_FROM_BYTE(&buffer[idx + \
119 i * TABLE_ENTRY_SIZE + \
120 OFFSET_FIRST_SEC]);
121 partition_entries[partition_count].size = \
122 GET_LWORD_FROM_BYTE(&buffer[idx + \
123 i * TABLE_ENTRY_SIZE + \
124 OFFSET_SIZE]);
125 dfirstsec = partition_entries[partition_count].first_lba;
126 mbr_fill_name(&partition_entries[partition_count], \
127 partition_entries[partition_count].dtype);
128 partition_count++;
129 if (partition_count == NUM_PARTITIONS)
130 return ret;
131 }
132
133 /* See if the last partition is EBR, if not, parsing is done */
134 if (dtype != MBR_EBR_TYPE)
135 {
136 return ret;
137 }
138
139 EBR_first_sec = dfirstsec;
140 EBR_current_sec = dfirstsec;
141
142 ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
143 (EBR_first_sec * 512), \
144 MMC_BOOT_RD_BLOCK_LEN, \
145 (unsigned int *)buffer);
146 if (ret)
147 {
148 return ret;
149 }
150 /* Loop to parse the EBR */
151 for (i = 0;; i++)
152 {
153 ret = partition_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, buffer);
154 if (ret)
155 {
156 ret = MMC_BOOT_E_SUCCESS;
157 break;
158 }
159 partition_entries[partition_count].attribute_flag = \
160 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
161 partition_entries[partition_count].dtype = \
162 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
163 partition_entries[partition_count].first_lba = \
164 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
165 OFFSET_FIRST_SEC]) + \
166 EBR_current_sec;
167 partition_entries[partition_count].size = \
168 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + \
169 OFFSET_SIZE]);
170 mbr_fill_name(&(partition_entries[partition_count]), \
171 partition_entries[partition_count].dtype);
172 partition_count++;
173 if (partition_count == NUM_PARTITIONS)
174 return ret;
175
176 dfirstsec =
177 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
178 if(dfirstsec == 0)
179 {
180 /* Getting to the end of the EBR tables */
181 break;
182 }
183 /* More EBR to follow - read in the next EBR sector */
184 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
185 + dfirstsec);
186 ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
187 ((EBR_first_sec + dfirstsec) * 512), \
188 MMC_BOOT_RD_BLOCK_LEN, \
189 (unsigned int *)buffer);
190 if (ret)
191 {
192 return ret;
193 }
194 EBR_current_sec = EBR_first_sec + dfirstsec;
195 }
196 return ret;
197}
Kinson Chik66552a82011-03-29 15:59:06 -0700198
199/*
200 * Read GPT from MMC and fill partition table
201 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700202unsigned int mmc_boot_read_gpt( struct mmc_boot_host * mmc_host,
203 struct mmc_boot_card * mmc_card)
204{
Kinson Chik66552a82011-03-29 15:59:06 -0700205
Kinson Chikf1a43512011-07-14 11:28:39 -0700206 int ret = MMC_BOOT_E_SUCCESS;
207 unsigned int header_size;
208 unsigned long long first_usable_lba;
Kinson Chik4d7444f2011-09-13 15:48:51 -0700209 unsigned long long backup_header_lba;
210 unsigned int max_partition_count = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700211 unsigned int partition_entry_size;
212 unsigned char data[MMC_BOOT_RD_BLOCK_LEN];
213 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];
Kinson Chik4d7444f2011-09-13 15:48:51 -0700217 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
218 unsigned long long partition_0 = 2;
Kinson Chik66552a82011-03-29 15:59:06 -0700219
220 /* Print out the GPT first */
Kinson Chikf1a43512011-07-14 11:28:39 -0700221 ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
222 PROTECTIVE_MBR_SIZE, \
223 MMC_BOOT_RD_BLOCK_LEN, \
224 (unsigned int *)data);
Kinson Chik66552a82011-03-29 15:59:06 -0700225
Kinson Chik4d7444f2011-09-13 15:48:51 -0700226 if (ret)
227 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Kinson Chik66552a82011-03-29 15:59:06 -0700228
Kinson Chik4d7444f2011-09-13 15:48:51 -0700229 ret = partition_parse_gpt_header(data, &first_usable_lba,
230 &partition_entry_size, &header_size,
231 &max_partition_count);
232
233 if (ret)
234 {
235 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n" );
236
237 /* Check the backup gpt */
238 backup_header_lba = GET_LLWORD_FROM_BYTE(&data[BACKUP_HEADER_OFFSET]);
239 ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
240 (backup_header_lba * BLOCK_SIZE), \
241 MMC_BOOT_RD_BLOCK_LEN, \
242 (unsigned int *)data);
243
244 if (ret)
245 {
246 dprintf(CRITICAL, "GPT: Could not read backup gpt from mmc\n");
247 return ret;
248 }
249
250 ret = partition_parse_gpt_header(data, &first_usable_lba,
251 &partition_entry_size, &header_size,
252 &max_partition_count);
253 if (ret)
254 {
255 dprintf(CRITICAL, "GPT: Primary and backup signatures invalid\n");
256 return ret;
257 }
258 partition_0 = backup_header_lba - (max_partition_count / 4);
259 }
Kinson Chik66552a82011-03-29 15:59:06 -0700260
261 /* Read GPT Entries */
Kinson Chikf1a43512011-07-14 11:28:39 -0700262 for(i = 0; i < (max_partition_count/4); i++)
Kinson Chik66552a82011-03-29 15:59:06 -0700263 {
264 ret = mmc_boot_read_from_card( mmc_host, mmc_card,
Kinson Chik4d7444f2011-09-13 15:48:51 -0700265 (partition_0 * BLOCK_SIZE) +
Kinson Chik66552a82011-03-29 15:59:06 -0700266 (i * MMC_BOOT_RD_BLOCK_LEN),
267 MMC_BOOT_RD_BLOCK_LEN,
268 (uint32_t *)data);
269
270 if (ret)
271 {
Kinson Chikf1a43512011-07-14 11:28:39 -0700272 dprintf(CRITICAL,
273 "GPT: mmc read card failed reading partition entries.\n" );
Kinson Chik66552a82011-03-29 15:59:06 -0700274 return ret;
275 }
276
277 for(j=0; j < 4; j++)
278 {
Kinson Chikf1a43512011-07-14 11:28:39 -0700279 memcpy(&(partition_entries[partition_count].type_guid),
280 &data[(j * partition_entry_size)],
281 PARTITION_TYPE_GUID_SIZE);
282 if (partition_entries[partition_count].type_guid[0] == 0x00 &&
283 partition_entries[partition_count].type_guid[1] == 0x00)
Kinson Chik66552a82011-03-29 15:59:06 -0700284 {
Kinson Chikf1a43512011-07-14 11:28:39 -0700285 i = max_partition_count;
Kinson Chik66552a82011-03-29 15:59:06 -0700286 break;
287 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700288 memcpy(&(partition_entries[partition_count].unique_partition_guid),
289 &data[(j * partition_entry_size) +
290 UNIQUE_GUID_OFFSET], UNIQUE_PARTITION_GUID_SIZE);
291 partition_entries[partition_count].first_lba =
292 GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
293 FIRST_LBA_OFFSET]);
294 partition_entries[partition_count].last_lba =
295 GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
296 LAST_LBA_OFFSET]);
297 partition_entries[partition_count].size =
298 partition_entries[partition_count].last_lba -
299 partition_entries[partition_count].first_lba;
300 partition_entries[partition_count].attribute_flag =
301 GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
302 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700303
Kinson Chikf1a43512011-07-14 11:28:39 -0700304 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] = UTF16_name[n*2];
314 }
315 partition_count++;
Kinson Chik66552a82011-03-29 15:59:06 -0700316 }
317 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700318
Kinson Chik66552a82011-03-29 15:59:06 -0700319 return ret;
320}
321
Kinson Chikf1a43512011-07-14 11:28:39 -0700322/*
323 * Fill name for android partition found.
324 */
325static void mbr_fill_name (struct partition_entry *partition_ent,
326 unsigned int type)
327{
328 switch(type)
329 {
330 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
331 case MBR_MODEM_TYPE:
332 case MBR_MODEM_TYPE2:
333 /* if already assigned last name available then return */
334 if(!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
335 return;
336 strcpy((char *)partition_ent->name,
337 (const char *)vfat_partitions[vfat_count]);
338 vfat_count++;
339 break;
340 case MBR_SBL1_TYPE:
341 memcpy(partition_ent->name,"sbl1",4);
342 break;
343 case MBR_SBL2_TYPE:
344 memcpy(partition_ent->name,"sbl2",4);
345 break;
346 case MBR_SBL3_TYPE:
347 memcpy(partition_ent->name,"sbl3",4);
348 break;
349 case MBR_RPM_TYPE:
350 memcpy(partition_ent->name,"rpm",3);
351 break;
352 case MBR_TZ_TYPE:
353 memcpy(partition_ent->name,"tz",2);
354 break;
355 case MBR_ABOOT_TYPE:
356 memcpy(partition_ent->name,"aboot",5);
357 break;
358 case MBR_BOOT_TYPE:
359 memcpy(partition_ent->name,"boot",4);
360 break;
361 case MBR_MODEM_ST1_TYPE:
362 memcpy(partition_ent->name,"modem_st1",9);
363 break;
364 case MBR_MODEM_ST2_TYPE:
365 memcpy(partition_ent->name,"modem_st2",9);
366 break;
367 case MBR_EFS2_TYPE:
368 memcpy(partition_ent->name,"efs2",4);
369 break;
370 case MBR_USERDATA_TYPE:
371 if (ext3_count == sizeof(ext3_partitions) / sizeof(char*))
372 return;
373 strcpy((char *)partition_ent->name,
374 (const char *)ext3_partitions[ext3_count]);
375 ext3_count++;
376 break;
377 case MBR_RECOVERY_TYPE:
378 memcpy(partition_ent->name,"recovery",8);
379 break;
380 case MBR_MISC_TYPE:
381 memcpy(partition_ent->name,"misc",4);
382 break;
383 };
384}
385
386/*
387 * Find index of parition in array of partition entries
388 */
389unsigned partition_get_index (const char * name)
390{
391 unsigned int input_string_length = strlen(name);
Kinson Chik66552a82011-03-29 15:59:06 -0700392 unsigned n;
393
Kinson Chikf1a43512011-07-14 11:28:39 -0700394 for(n = 0; n < partition_count; n++){
395 if(!memcmp(name, &partition_entries[n].name, input_string_length) &&
396 input_string_length == strlen((const char *)&partition_entries[n].name))
397 {
398 return n;
Kinson Chik66552a82011-03-29 15:59:06 -0700399 }
400 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700401 return INVALID_PTN;
402}
403
404/* Get size of the partition */
405unsigned long long partition_get_size (int index)
406{
407 if (index == INVALID_PTN)
408 return 0;
409 else{
410 return partition_entries[index].size * MMC_BOOT_RD_BLOCK_LEN;
411 }
412}
413
414/* Get offset of the partition */
415unsigned long long partition_get_offset (int index)
416{
417 if (index == INVALID_PTN)
418 return 0;
419 else{
420 return partition_entries[index].first_lba * MMC_BOOT_RD_BLOCK_LEN;
421 }
422}
423
424/* Debug: Print all parsed partitions */
425void partition_dump()
426{
427 unsigned i = 0;
428 for (i=0; i< partition_count; i++){
429 dprintf(SPEW,
430 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
431 i, partition_entries[i].name, partition_entries[i].size,
432 partition_entries[i].dtype, partition_entries[i].first_lba,
433 partition_entries[i].last_lba);
434 }
435}
436
437unsigned int partition_verify_mbr_signature(unsigned size,
438 unsigned char* buffer)
439{
440 /* Avoid checking past end of buffer */
441 if ((TABLE_SIGNATURE + 1) > size)
442 {
443 return MMC_BOOT_E_FAILURE;
444 }
445 /* Check to see if signature exists */
446 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) || \
447 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1))
448 {
449 dprintf(CRITICAL, "MBR signature does not match. \n" );
450 return MMC_BOOT_E_FAILURE;
451 }
452 return MMC_BOOT_E_SUCCESS;
453}
454
455unsigned int mbr_partition_get_type(unsigned size, unsigned char* partition,
456 unsigned int *partition_type)
457{
458 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
459
460 if (size < type_offset)
461 {
462 goto end;
463 }
464
465 *partition_type = partition[type_offset];
466end:
467 return MMC_BOOT_E_SUCCESS;
468}
469
470unsigned int partition_get_type(unsigned size, unsigned char* partition,
471 unsigned int *partition_type)
472{
473 unsigned int ret = MMC_BOOT_E_SUCCESS;
474
475 /*
476 * If the block contains the MBR signature, then it's likely either
477 * MBR or MBR with protective type (GPT). If the MBR signature is
478 * not there, then it could be the GPT backup.
479 */
480
481 /* First check the MBR signature */
482 ret = partition_verify_mbr_signature(size, partition);
483 if (ret == MMC_BOOT_E_SUCCESS)
484 {
485 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
486
487 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
488 ret = mbr_partition_get_type(size, partition, &mbr_partition_type);
489 if (ret != MMC_BOOT_E_SUCCESS)
490 {
491 dprintf(CRITICAL, "Cannot get TYPE of partition");
492 }
493 else if (MBR_PROTECTED_TYPE == mbr_partition_type)
494 {
495 *partition_type = PARTITION_TYPE_GPT;
496 }
497 else
498 {
499 *partition_type = PARTITION_TYPE_MBR;
500 }
501 }
502 else
503 {
504 /*
505 * This could be the GPT backup. Make that assumption for now.
506 * Anybody who treats the block as GPT backup should check the
507 * signature.
508 */
509 *partition_type = PARTITION_TYPE_GPT_BACKUP;
510 }
511 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700512}
Kinson Chik4d7444f2011-09-13 15:48:51 -0700513
514/*
515 * Parse the gpt header and get the required header fields
516 * Return 0 on valid signature
517 */
518unsigned int partition_parse_gpt_header(unsigned char * buffer,
519 unsigned long long * first_usable_lba,
520 unsigned long * partition_entry_size,
521 unsigned long * header_size,
522 unsigned int * max_partition_count)
523{
524 /* Check GPT Signature */
525 if( ((uint32_t *)buffer)[0] != GPT_SIGNATURE_2 ||
526 ((uint32_t *)buffer)[1] != GPT_SIGNATURE_1 )
527 return 1;
528
529 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
530 *first_usable_lba = GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
531 *max_partition_count = GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
532 *partition_entry_size = GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
533
534 return 0;
535}