blob: 23d477860a201c90dbd692c818de8d198de602da [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;
209 unsigned int max_partition_count;
210 unsigned int partition_entry_size;
211 unsigned char data[MMC_BOOT_RD_BLOCK_LEN];
212 unsigned int i = 0; /* Counter for each 512 block */
213 unsigned int j = 0; /* Counter for each 128 entry in the 512 block */
214 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
215 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
Kinson Chik66552a82011-03-29 15:59:06 -0700216
217 /* Print out the GPT first */
Kinson Chikf1a43512011-07-14 11:28:39 -0700218 ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
219 PROTECTIVE_MBR_SIZE, \
220 MMC_BOOT_RD_BLOCK_LEN, \
221 (unsigned int *)data);
Kinson Chik66552a82011-03-29 15:59:06 -0700222
223 /* Check GPT Signature */
224 if( ((uint32_t *)data)[0] != GPT_SIGNATURE_2 ||
225 ((uint32_t *)data)[1] != GPT_SIGNATURE_1 )
226 {
227 dprintf(CRITICAL, "GPT: signature does not match.\n" );
228 return MMC_BOOT_E_FAILURE;
229 }
230
231 header_size = GET_LWORD_FROM_BYTE(&data[HEADER_SIZE_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700232 first_usable_lba = GET_LLWORD_FROM_BYTE(&data[FIRST_USABLE_LBA_OFFSET]);
Kinson Chikf1a43512011-07-14 11:28:39 -0700233 max_partition_count = GET_LWORD_FROM_BYTE(&data[PARTITION_COUNT_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700234 partition_entry_size = GET_LWORD_FROM_BYTE(&data[PENTRY_SIZE_OFFSET]);
235
236 /* Read GPT Entries */
Kinson Chikf1a43512011-07-14 11:28:39 -0700237 for(i = 0; i < (max_partition_count/4); i++)
Kinson Chik66552a82011-03-29 15:59:06 -0700238 {
239 ret = mmc_boot_read_from_card( mmc_host, mmc_card,
Kinson Chikf1a43512011-07-14 11:28:39 -0700240 PROTECTIVE_MBR_SIZE +
241 PARTITION_TABLE_SIZE +
Kinson Chik66552a82011-03-29 15:59:06 -0700242 (i * MMC_BOOT_RD_BLOCK_LEN),
243 MMC_BOOT_RD_BLOCK_LEN,
244 (uint32_t *)data);
245
246 if (ret)
247 {
Kinson Chikf1a43512011-07-14 11:28:39 -0700248 dprintf(CRITICAL,
249 "GPT: mmc read card failed reading partition entries.\n" );
Kinson Chik66552a82011-03-29 15:59:06 -0700250 return ret;
251 }
252
253 for(j=0; j < 4; j++)
254 {
Kinson Chikf1a43512011-07-14 11:28:39 -0700255 memcpy(&(partition_entries[partition_count].type_guid),
256 &data[(j * partition_entry_size)],
257 PARTITION_TYPE_GUID_SIZE);
258 if (partition_entries[partition_count].type_guid[0] == 0x00 &&
259 partition_entries[partition_count].type_guid[1] == 0x00)
Kinson Chik66552a82011-03-29 15:59:06 -0700260 {
Kinson Chikf1a43512011-07-14 11:28:39 -0700261 i = max_partition_count;
Kinson Chik66552a82011-03-29 15:59:06 -0700262 break;
263 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700264 memcpy(&(partition_entries[partition_count].unique_partition_guid),
265 &data[(j * partition_entry_size) +
266 UNIQUE_GUID_OFFSET], UNIQUE_PARTITION_GUID_SIZE);
267 partition_entries[partition_count].first_lba =
268 GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
269 FIRST_LBA_OFFSET]);
270 partition_entries[partition_count].last_lba =
271 GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
272 LAST_LBA_OFFSET]);
273 partition_entries[partition_count].size =
274 partition_entries[partition_count].last_lba -
275 partition_entries[partition_count].first_lba;
276 partition_entries[partition_count].attribute_flag =
277 GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
278 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700279
Kinson Chikf1a43512011-07-14 11:28:39 -0700280 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
281 memcpy(UTF16_name, &data[(j * partition_entry_size) +
282 PARTITION_NAME_OFFSET],
283 MAX_GPT_NAME_SIZE);
284 /*
285 * Currently partition names in *.xml are UTF-8 and lowercase
286 * Only supporting english for now so removing 2nd byte of UTF-16
287 */
288 for(n = 0; n < MAX_GPT_NAME_SIZE/2; n++){
289 partition_entries[partition_count].name[n] = UTF16_name[n*2];
290 }
291 partition_count++;
Kinson Chik66552a82011-03-29 15:59:06 -0700292 }
293 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700294
Kinson Chik66552a82011-03-29 15:59:06 -0700295 return ret;
296}
297
Kinson Chikf1a43512011-07-14 11:28:39 -0700298/*
299 * Fill name for android partition found.
300 */
301static void mbr_fill_name (struct partition_entry *partition_ent,
302 unsigned int type)
303{
304 switch(type)
305 {
306 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
307 case MBR_MODEM_TYPE:
308 case MBR_MODEM_TYPE2:
309 /* if already assigned last name available then return */
310 if(!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
311 return;
312 strcpy((char *)partition_ent->name,
313 (const char *)vfat_partitions[vfat_count]);
314 vfat_count++;
315 break;
316 case MBR_SBL1_TYPE:
317 memcpy(partition_ent->name,"sbl1",4);
318 break;
319 case MBR_SBL2_TYPE:
320 memcpy(partition_ent->name,"sbl2",4);
321 break;
322 case MBR_SBL3_TYPE:
323 memcpy(partition_ent->name,"sbl3",4);
324 break;
325 case MBR_RPM_TYPE:
326 memcpy(partition_ent->name,"rpm",3);
327 break;
328 case MBR_TZ_TYPE:
329 memcpy(partition_ent->name,"tz",2);
330 break;
331 case MBR_ABOOT_TYPE:
332 memcpy(partition_ent->name,"aboot",5);
333 break;
334 case MBR_BOOT_TYPE:
335 memcpy(partition_ent->name,"boot",4);
336 break;
337 case MBR_MODEM_ST1_TYPE:
338 memcpy(partition_ent->name,"modem_st1",9);
339 break;
340 case MBR_MODEM_ST2_TYPE:
341 memcpy(partition_ent->name,"modem_st2",9);
342 break;
343 case MBR_EFS2_TYPE:
344 memcpy(partition_ent->name,"efs2",4);
345 break;
346 case MBR_USERDATA_TYPE:
347 if (ext3_count == sizeof(ext3_partitions) / sizeof(char*))
348 return;
349 strcpy((char *)partition_ent->name,
350 (const char *)ext3_partitions[ext3_count]);
351 ext3_count++;
352 break;
353 case MBR_RECOVERY_TYPE:
354 memcpy(partition_ent->name,"recovery",8);
355 break;
356 case MBR_MISC_TYPE:
357 memcpy(partition_ent->name,"misc",4);
358 break;
359 };
360}
361
362/*
363 * Find index of parition in array of partition entries
364 */
365unsigned partition_get_index (const char * name)
366{
367 unsigned int input_string_length = strlen(name);
Kinson Chik66552a82011-03-29 15:59:06 -0700368 unsigned n;
369
Kinson Chikf1a43512011-07-14 11:28:39 -0700370 for(n = 0; n < partition_count; n++){
371 if(!memcmp(name, &partition_entries[n].name, input_string_length) &&
372 input_string_length == strlen((const char *)&partition_entries[n].name))
373 {
374 return n;
Kinson Chik66552a82011-03-29 15:59:06 -0700375 }
376 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700377 return INVALID_PTN;
378}
379
380/* Get size of the partition */
381unsigned long long partition_get_size (int index)
382{
383 if (index == INVALID_PTN)
384 return 0;
385 else{
386 return partition_entries[index].size * MMC_BOOT_RD_BLOCK_LEN;
387 }
388}
389
390/* Get offset of the partition */
391unsigned long long partition_get_offset (int index)
392{
393 if (index == INVALID_PTN)
394 return 0;
395 else{
396 return partition_entries[index].first_lba * MMC_BOOT_RD_BLOCK_LEN;
397 }
398}
399
400/* Debug: Print all parsed partitions */
401void partition_dump()
402{
403 unsigned i = 0;
404 for (i=0; i< partition_count; i++){
405 dprintf(SPEW,
406 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
407 i, partition_entries[i].name, partition_entries[i].size,
408 partition_entries[i].dtype, partition_entries[i].first_lba,
409 partition_entries[i].last_lba);
410 }
411}
412
413unsigned int partition_verify_mbr_signature(unsigned size,
414 unsigned char* buffer)
415{
416 /* Avoid checking past end of buffer */
417 if ((TABLE_SIGNATURE + 1) > size)
418 {
419 return MMC_BOOT_E_FAILURE;
420 }
421 /* Check to see if signature exists */
422 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) || \
423 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1))
424 {
425 dprintf(CRITICAL, "MBR signature does not match. \n" );
426 return MMC_BOOT_E_FAILURE;
427 }
428 return MMC_BOOT_E_SUCCESS;
429}
430
431unsigned int mbr_partition_get_type(unsigned size, unsigned char* partition,
432 unsigned int *partition_type)
433{
434 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
435
436 if (size < type_offset)
437 {
438 goto end;
439 }
440
441 *partition_type = partition[type_offset];
442end:
443 return MMC_BOOT_E_SUCCESS;
444}
445
446unsigned int partition_get_type(unsigned size, unsigned char* partition,
447 unsigned int *partition_type)
448{
449 unsigned int ret = MMC_BOOT_E_SUCCESS;
450
451 /*
452 * If the block contains the MBR signature, then it's likely either
453 * MBR or MBR with protective type (GPT). If the MBR signature is
454 * not there, then it could be the GPT backup.
455 */
456
457 /* First check the MBR signature */
458 ret = partition_verify_mbr_signature(size, partition);
459 if (ret == MMC_BOOT_E_SUCCESS)
460 {
461 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
462
463 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
464 ret = mbr_partition_get_type(size, partition, &mbr_partition_type);
465 if (ret != MMC_BOOT_E_SUCCESS)
466 {
467 dprintf(CRITICAL, "Cannot get TYPE of partition");
468 }
469 else if (MBR_PROTECTED_TYPE == mbr_partition_type)
470 {
471 *partition_type = PARTITION_TYPE_GPT;
472 }
473 else
474 {
475 *partition_type = PARTITION_TYPE_MBR;
476 }
477 }
478 else
479 {
480 /*
481 * This could be the GPT backup. Make that assumption for now.
482 * Anybody who treats the block as GPT backup should check the
483 * signature.
484 */
485 *partition_type = PARTITION_TYPE_GPT_BACKUP;
486 }
487 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700488}