blob: 55340243585977bab3d517f170df3f231fb26ce3 [file] [log] [blame]
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -08001/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
Kinson Chik66552a82011-03-29 15:59:06 -07002
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
Channagoud Kadabif73aa292013-01-31 16:55:20 -080012 * * Neither the name of The Linux Foundation. nor the names of its
Kinson Chik66552a82011-03-29 15:59:06 -070013 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <stdlib.h>
30#include <string.h>
31#include "mmc.h"
32#include "partition_parser.h"
33
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -080034__WEAK void mmc_set_lun(uint8_t lun)
35{
36}
37
38__WEAK uint8_t mmc_get_lun(void)
39{
40 return 0;
41}
42
43__WEAK void mmc_read_partition_table(uint8_t arg)
44{
45 if(partition_read_table())
46 {
47 dprintf(CRITICAL, "Error reading the partition table info\n");
48 ASSERT(0);
49 }
50}
51
Channagoud Kadabi96c629e2013-09-10 14:21:30 -070052static uint32_t mmc_boot_read_gpt(uint32_t block_size);
53static uint32_t mmc_boot_read_mbr(uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070054static void mbr_fill_name(struct partition_entry *partition_ent,
55 uint32_t type);
56static uint32_t partition_verify_mbr_signature(uint32_t size,
57 uint8_t *buffer);
58static uint32_t mbr_partition_get_type(uint32_t size, uint8_t *partition,
59 uint32_t *partition_type);
60
61static uint32_t partition_get_type(uint32_t size, uint8_t *partition,
62 uint32_t *partition_type);
63static uint32_t partition_parse_gpt_header(uint8_t *buffer,
64 uint64_t *first_usable_lba,
65 uint32_t *partition_entry_size,
66 uint32_t *header_size,
67 uint32_t *max_partition_count);
68
Channagoud Kadabi96c629e2013-09-10 14:21:30 -070069static uint32_t write_mbr(uint32_t, uint8_t *mbrImage, uint32_t block_size);
70static uint32_t write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070071
Ajay Dudanib01e5062011-12-03 23:23:42 -080072char *ext3_partitions[] =
73 { "system", "userdata", "persist", "cache", "tombstones" };
74char *vfat_partitions[] = { "modem", "mdm", "NONE" };
75
Kinson Chikf1a43512011-07-14 11:28:39 -070076unsigned int ext3_count = 0;
77unsigned int vfat_count = 0;
78
Channagoud Kadabie9cb1c22013-11-12 13:49:41 -080079struct partition_entry *partition_entries;
Pavel Nedevb5ba62d2013-07-22 11:57:41 +030080static unsigned gpt_partitions_exist = 0;
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -080081static unsigned partition_count;
Kinson Chikf1a43512011-07-14 11:28:39 -070082
Channagoud Kadabi0e332852013-04-19 12:55:53 -070083unsigned int partition_read_table()
Kinson Chikf1a43512011-07-14 11:28:39 -070084{
Ajay Dudanib01e5062011-12-03 23:23:42 -080085 unsigned int ret;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -070086 uint32_t block_size;
87
88 block_size = mmc_get_device_blocksize();
Kinson Chikf1a43512011-07-14 11:28:39 -070089
Channagoud Kadabie9cb1c22013-11-12 13:49:41 -080090 /* Allocate partition entries array */
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -080091 if(!partition_entries)
92 {
93 partition_entries = (struct partition_entry *) calloc(NUM_PARTITIONS, sizeof(struct partition_entry));
94 ASSERT(partition_entries);
95 }
Channagoud Kadabie9cb1c22013-11-12 13:49:41 -080096
Ajay Dudanib01e5062011-12-03 23:23:42 -080097 /* Read MBR of the card */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -070098 ret = mmc_boot_read_mbr(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070099 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800100 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700101 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800102 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700103
Ajay Dudanib01e5062011-12-03 23:23:42 -0800104 /* Read GPT of the card if exist */
105 if (gpt_partitions_exist) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700106 ret = mmc_boot_read_gpt(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700107 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800108 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700109 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800110 }
111 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700112 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700113}
114
115/*
116 * Read MBR from MMC card and fill partition table.
117 */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700118static unsigned int mmc_boot_read_mbr(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700119{
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700120 uint8_t *buffer = NULL;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800121 unsigned int dtype;
122 unsigned int dfirstsec;
123 unsigned int EBR_first_sec;
124 unsigned int EBR_current_sec;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700125 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800126 int idx, i;
Kinson Chikf1a43512011-07-14 11:28:39 -0700127
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700128 buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
129
130 if (!buffer)
131 {
132 dprintf(CRITICAL, "Error allocating memory while reading partition table\n");
133 ret = -1;
134 goto end;
135 }
136
Ajay Dudanib01e5062011-12-03 23:23:42 -0800137 /* Print out the MBR first */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700138 ret = mmc_read(0, (unsigned int *)buffer, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800139 if (ret) {
140 dprintf(CRITICAL, "Could not read partition from mmc\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700141 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800142 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700143
Ajay Dudanib01e5062011-12-03 23:23:42 -0800144 /* Check to see if signature exists */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700145 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800146 if (ret) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700147 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800148 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700149
Ajay Dudanib01e5062011-12-03 23:23:42 -0800150 /*
151 * Process each of the four partitions in the MBR by reading the table
152 * information into our mbr table.
153 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800154 idx = TABLE_ENTRY_0;
155 for (i = 0; i < 4; i++) {
156 /* Type 0xEE indicates end of MBR and GPT partitions exist */
157 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
158 if (dtype == MBR_PROTECTED_TYPE) {
159 gpt_partitions_exist = 1;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700160 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800161 }
162 partition_entries[partition_count].dtype = dtype;
163 partition_entries[partition_count].attribute_flag =
164 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
165 partition_entries[partition_count].first_lba =
166 GET_LWORD_FROM_BYTE(&buffer[idx +
167 i * TABLE_ENTRY_SIZE +
168 OFFSET_FIRST_SEC]);
169 partition_entries[partition_count].size =
170 GET_LWORD_FROM_BYTE(&buffer[idx +
171 i * TABLE_ENTRY_SIZE +
172 OFFSET_SIZE]);
173 dfirstsec = partition_entries[partition_count].first_lba;
174 mbr_fill_name(&partition_entries[partition_count],
175 partition_entries[partition_count].dtype);
176 partition_count++;
177 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700178 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800179 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700180
Ajay Dudanib01e5062011-12-03 23:23:42 -0800181 /* See if the last partition is EBR, if not, parsing is done */
182 if (dtype != MBR_EBR_TYPE) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700183 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800184 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700185
Ajay Dudanib01e5062011-12-03 23:23:42 -0800186 EBR_first_sec = dfirstsec;
187 EBR_current_sec = dfirstsec;
Kinson Chikf1a43512011-07-14 11:28:39 -0700188
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700189 ret = mmc_read((EBR_first_sec * block_size), (unsigned int *)buffer, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700190 if (ret)
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700191 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700192
Ajay Dudanib01e5062011-12-03 23:23:42 -0800193 /* Loop to parse the EBR */
194 for (i = 0;; i++) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700195 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800196 if (ret) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700197 ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800198 break;
199 }
200 partition_entries[partition_count].attribute_flag =
201 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
202 partition_entries[partition_count].dtype =
203 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
204 partition_entries[partition_count].first_lba =
205 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
206 OFFSET_FIRST_SEC]) +
207 EBR_current_sec;
208 partition_entries[partition_count].size =
209 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
210 mbr_fill_name(&(partition_entries[partition_count]),
211 partition_entries[partition_count].dtype);
212 partition_count++;
213 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700214 goto end;
Kinson Chikf1a43512011-07-14 11:28:39 -0700215
Ajay Dudanib01e5062011-12-03 23:23:42 -0800216 dfirstsec =
217 GET_LWORD_FROM_BYTE(&buffer
218 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
219 if (dfirstsec == 0) {
220 /* Getting to the end of the EBR tables */
221 break;
222 }
223 /* More EBR to follow - read in the next EBR sector */
224 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
225 + dfirstsec);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700226 ret = mmc_read(((EBR_first_sec + dfirstsec) * block_size),(unsigned int *)buffer,
227 block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700228 if (ret)
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700229 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700230
Ajay Dudanib01e5062011-12-03 23:23:42 -0800231 EBR_current_sec = EBR_first_sec + dfirstsec;
232 }
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700233end:
234 if (buffer)
235 free(buffer);
236
Ajay Dudanib01e5062011-12-03 23:23:42 -0800237 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700238}
Kinson Chik66552a82011-03-29 15:59:06 -0700239
240/*
241 * Read GPT from MMC and fill partition table
242 */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700243static unsigned int mmc_boot_read_gpt(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700244{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700245 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800246 unsigned int header_size;
247 unsigned long long first_usable_lba;
248 unsigned long long backup_header_lba;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700249 unsigned long long card_size_sec;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800250 unsigned int max_partition_count = 0;
251 unsigned int partition_entry_size;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700252 unsigned int i = 0; /* Counter for each block */
253 unsigned int j = 0; /* Counter for each entry in a block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800254 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
255 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
256 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700257 unsigned long long partition_0;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700258 uint64_t device_density;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700259 uint8_t *data = NULL;
260 uint32_t part_entry_cnt = block_size / ENTRY_SIZE;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700261
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700262 /* Get the density of the mmc device */
263
264 device_density = mmc_get_device_capacity();
265
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700266 data = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
267 if (!data)
268 {
269 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
270 ret = -1;
271 goto end;
272 }
273
Ajay Dudanib01e5062011-12-03 23:23:42 -0800274 /* Print out the GPT first */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700275 ret = mmc_read(block_size, (unsigned int *)data, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700276 if (ret)
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700277 {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800278 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700279 goto end;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700280 }
Kinson Chik66552a82011-03-29 15:59:06 -0700281
Ajay Dudanib01e5062011-12-03 23:23:42 -0800282 ret = partition_parse_gpt_header(data, &first_usable_lba,
283 &partition_entry_size, &header_size,
284 &max_partition_count);
285 if (ret) {
286 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700287
Ajay Dudanib01e5062011-12-03 23:23:42 -0800288 /* Check the backup gpt */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700289
290 /* Get size of MMC */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700291 card_size_sec = (device_density) / block_size;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700292 ASSERT (card_size_sec > 0);
293
294 backup_header_lba = card_size_sec - 1;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700295 ret = mmc_read((backup_header_lba * block_size), (unsigned int *)data,
296 block_size);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700297
Ajay Dudanib01e5062011-12-03 23:23:42 -0800298 if (ret) {
299 dprintf(CRITICAL,
300 "GPT: Could not read backup gpt from mmc\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700301 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800302 }
Kinson Chik4d7444f2011-09-13 15:48:51 -0700303
Ajay Dudanib01e5062011-12-03 23:23:42 -0800304 ret = partition_parse_gpt_header(data, &first_usable_lba,
305 &partition_entry_size,
306 &header_size,
307 &max_partition_count);
308 if (ret) {
309 dprintf(CRITICAL,
310 "GPT: Primary and backup signatures invalid\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700311 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800312 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800313 }
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700314 partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800315 /* Read GPT Entries */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700316 for (i = 0; i < (ROUNDUP(max_partition_count, part_entry_cnt)) / part_entry_cnt; i++) {
neetid6c38de12011-12-02 12:04:50 -0800317 ASSERT(partition_count < NUM_PARTITIONS);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700318 ret = mmc_read((partition_0 * block_size) + (i * block_size),
319 (uint32_t *) data, block_size);
Kinson Chik66552a82011-03-29 15:59:06 -0700320
Ajay Dudanib01e5062011-12-03 23:23:42 -0800321 if (ret) {
322 dprintf(CRITICAL,
323 "GPT: mmc read card failed reading partition entries.\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700324 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800325 }
Kinson Chik66552a82011-03-29 15:59:06 -0700326
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700327 for (j = 0; j < part_entry_cnt; j++) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800328 memcpy(&(partition_entries[partition_count].type_guid),
329 &data[(j * partition_entry_size)],
330 PARTITION_TYPE_GUID_SIZE);
331 if (partition_entries[partition_count].type_guid[0] ==
332 0x00
333 && partition_entries[partition_count].
334 type_guid[1] == 0x00) {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700335 i = ROUNDUP(max_partition_count, part_entry_cnt);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800336 break;
337 }
338 memcpy(&
339 (partition_entries[partition_count].
340 unique_partition_guid),
341 &data[(j * partition_entry_size) +
342 UNIQUE_GUID_OFFSET],
343 UNIQUE_PARTITION_GUID_SIZE);
344 partition_entries[partition_count].first_lba =
345 GET_LLWORD_FROM_BYTE(&data
346 [(j * partition_entry_size) +
347 FIRST_LBA_OFFSET]);
348 partition_entries[partition_count].last_lba =
349 GET_LLWORD_FROM_BYTE(&data
350 [(j * partition_entry_size) +
351 LAST_LBA_OFFSET]);
352 partition_entries[partition_count].size =
353 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700354 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800355 partition_entries[partition_count].attribute_flag =
356 GET_LLWORD_FROM_BYTE(&data
357 [(j * partition_entry_size) +
358 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700359
Ajay Dudanib01e5062011-12-03 23:23:42 -0800360 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
361 memcpy(UTF16_name, &data[(j * partition_entry_size) +
362 PARTITION_NAME_OFFSET],
363 MAX_GPT_NAME_SIZE);
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -0800364 partition_entries[partition_count].lun = mmc_get_lun();
365
Ajay Dudanib01e5062011-12-03 23:23:42 -0800366 /*
367 * Currently partition names in *.xml are UTF-8 and lowercase
368 * Only supporting english for now so removing 2nd byte of UTF-16
369 */
370 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
371 partition_entries[partition_count].name[n] =
372 UTF16_name[n * 2];
373 }
374 partition_count++;
375 }
376 }
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700377end:
378 if (data)
379 free(data);
380
Ajay Dudanib01e5062011-12-03 23:23:42 -0800381 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700382}
383
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700384static unsigned int write_mbr_in_blocks(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700385{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800386 unsigned int dtype;
387 unsigned int dfirstsec;
388 unsigned int ebrSectorOffset;
389 unsigned char *ebrImage;
390 unsigned char *lastAddress;
391 int idx, i;
392 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700393
Ajay Dudanib01e5062011-12-03 23:23:42 -0800394 /* Write the first block */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700395 ret = mmc_write(0, block_size, (unsigned int *)mbrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800396 if (ret) {
397 dprintf(CRITICAL, "Failed to write mbr partition\n");
398 goto end;
399 }
400 dprintf(SPEW, "write of first MBR block ok\n");
401 /*
402 Loop through the MBR table to see if there is an EBR.
403 If found, then figure out where to write the first EBR
404 */
405 idx = TABLE_ENTRY_0;
406 for (i = 0; i < 4; i++) {
407 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
408 if (MBR_EBR_TYPE == dtype) {
409 dprintf(SPEW, "EBR found.\n");
410 break;
411 }
412 }
413 if (MBR_EBR_TYPE != dtype) {
414 dprintf(SPEW, "No EBR in this image\n");
415 goto end;
416 }
417 /* EBR exists. Write each EBR block to mmc */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700418 ebrImage = mbrImage + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800419 ebrSectorOffset =
420 GET_LWORD_FROM_BYTE(&mbrImage
421 [idx + i * TABLE_ENTRY_SIZE +
422 OFFSET_FIRST_SEC]);
423 dfirstsec = 0;
424 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
425 lastAddress = mbrImage + size;
426 while (ebrImage < lastAddress) {
427 dprintf(SPEW, "writing to 0x%X\n",
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700428 (ebrSectorOffset + dfirstsec) * block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800429 ret =
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700430 mmc_write((ebrSectorOffset + dfirstsec) * block_size,
431 block_size, (unsigned int *)ebrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800432 if (ret) {
433 dprintf(CRITICAL,
434 "Failed to write EBR block to sector 0x%X\n",
435 dfirstsec);
436 goto end;
437 }
438 dfirstsec =
439 GET_LWORD_FROM_BYTE(&ebrImage
440 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700441 ebrImage += block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800442 }
443 dprintf(INFO, "MBR written to mmc successfully\n");
444 end:
445 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700446}
447
448/* Write the MBR/EBR to the MMC. */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700449static unsigned int write_mbr(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700450{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800451 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700452
Ajay Dudanib01e5062011-12-03 23:23:42 -0800453 /* Verify that passed in block is a valid MBR */
454 ret = partition_verify_mbr_signature(size, mbrImage);
455 if (ret) {
456 goto end;
457 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700458
Ajay Dudanib01e5062011-12-03 23:23:42 -0800459 /* Write the MBR/EBR to mmc */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700460 ret = write_mbr_in_blocks(size, mbrImage, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800461 if (ret) {
462 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
463 goto end;
464 }
465 /* Re-read the MBR partition into mbr table */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700466 ret = mmc_boot_read_mbr(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800467 if (ret) {
468 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
469 goto end;
470 }
471 partition_dump();
472 end:
473 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700474}
475
476/*
477 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
478*/
479int reflect(int data, int len)
480{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800481 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700482
Ajay Dudanib01e5062011-12-03 23:23:42 -0800483 for (int i = 0; i < len; i++) {
484 if (data & 0x1) {
485 ref |= (1 << ((len - 1) - i));
486 }
487 data = (data >> 1);
488 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700489
Ajay Dudanib01e5062011-12-03 23:23:42 -0800490 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700491}
492
493/*
494* Function to calculate the CRC32
495*/
496unsigned int calculate_crc32(unsigned char *buffer, int len)
497{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800498 int byte_length = 8; /*length of unit (i.e. byte) */
499 int msb = 0;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700500 int polynomial = 0x04C11DB7; /* IEEE 32bit polynomial */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800501 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
502 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
503 int regs_msb = 0;
504 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700505
Ajay Dudanib01e5062011-12-03 23:23:42 -0800506 for (int i = 0; i < len; i++) {
507 int data_byte = buffer[i];
508 data_byte = reflect(data_byte, 8);
509 for (int j = 0; j < byte_length; j++) {
510 msb = data_byte >> (byte_length - 1); /* get MSB */
511 msb &= 1; /* ensure just 1 bit */
512 regs_msb = (regs >> 31) & 1; /* MSB of regs */
513 regs = regs << 1; /* shift regs for CRC-CCITT */
514 if (regs_msb ^ msb) { /* MSB is a 1 */
515 regs = regs ^ polynomial; /* XOR with generator poly */
516 }
517 regs = regs & regs_mask; /* Mask off excess upper bits */
518 data_byte <<= 1; /* get to next bit */
519 }
520 }
521 regs = regs & regs_mask;
522 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700523
Ajay Dudanib01e5062011-12-03 23:23:42 -0800524 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700525}
526
527/*
528 * Write the GPT Partition Entry Array to the MMC.
529 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800530static unsigned int
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700531write_gpt_partition_array(uint8_t *header,
532 uint32_t partition_array_start,
533 uint32_t array_size,
534 uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700535{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700536 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800537 unsigned long long partition_entry_lba;
538 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700539
Ajay Dudanib01e5062011-12-03 23:23:42 -0800540 partition_entry_lba =
541 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700542 partition_entry_array_start_location = partition_entry_lba * block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700543
Ajay Dudanib01e5062011-12-03 23:23:42 -0800544 ret = mmc_write(partition_entry_array_start_location, array_size,
545 (unsigned int *)partition_array_start);
546 if (ret) {
547 dprintf(CRITICAL,
548 "GPT: FAILED to write the partition entry array\n");
549 goto end;
550 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700551
Ajay Dudanib01e5062011-12-03 23:23:42 -0800552 end:
553 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700554}
555
Ajay Dudanib01e5062011-12-03 23:23:42 -0800556static void
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700557patch_gpt(uint8_t *gptImage, uint64_t density, uint32_t array_size,
558 uint32_t max_part_count, uint32_t part_entry_size, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700559{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800560 unsigned int partition_entry_array_start;
561 unsigned char *primary_gpt_header;
562 unsigned char *secondary_gpt_header;
563 unsigned int offset;
564 unsigned long long card_size_sec;
565 int total_part = 0;
566 unsigned int last_part_offset;
567 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700568
Ajay Dudanib01e5062011-12-03 23:23:42 -0800569 /* Get size of MMC */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700570 card_size_sec = (density) / block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800571 /* Working around cap at 4GB */
572 if (card_size_sec == 0) {
573 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
574 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700575
Ajay Dudanib01e5062011-12-03 23:23:42 -0800576 /* Patching primary header */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700577 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800578 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
579 ((long long)(card_size_sec - 1)));
580 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
581 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700582
Ajay Dudanib01e5062011-12-03 23:23:42 -0800583 /* Patching backup GPT */
584 offset = (2 * array_size);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700585 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800586 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
587 ((long long)(card_size_sec - 1)));
588 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
589 ((long long)(card_size_sec - 34)));
590 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
591 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700592
Ajay Dudanib01e5062011-12-03 23:23:42 -0800593 /* Find last partition */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700594 while (*(primary_gpt_header + block_size + total_part * ENTRY_SIZE) !=
Ajay Dudanib01e5062011-12-03 23:23:42 -0800595 0) {
596 total_part++;
597 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700598
Ajay Dudanib01e5062011-12-03 23:23:42 -0800599 /* Patching last partition */
600 last_part_offset =
601 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700602 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800603 (long long)(card_size_sec - 34));
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700604 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800605 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700606
Ajay Dudanib01e5062011-12-03 23:23:42 -0800607 /* Updating CRC of the Partition entry array in both headers */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700608 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800609 crc_value = calculate_crc32(partition_entry_array_start,
610 max_part_count * part_entry_size);
611 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700612
Ajay Dudanib01e5062011-12-03 23:23:42 -0800613 crc_value = calculate_crc32(partition_entry_array_start + array_size,
614 max_part_count * part_entry_size);
615 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700616
Ajay Dudanib01e5062011-12-03 23:23:42 -0800617 /* Clearing CRC fields to calculate */
618 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
619 crc_value = calculate_crc32(primary_gpt_header, 92);
620 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700621
Ajay Dudanib01e5062011-12-03 23:23:42 -0800622 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
623 crc_value = (calculate_crc32(secondary_gpt_header, 92));
624 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700625
626}
627
628/*
629 * Write the GPT to the MMC.
630 */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700631static unsigned int write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700632{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700633 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800634 unsigned int header_size;
635 unsigned long long first_usable_lba;
636 unsigned long long backup_header_lba;
637 unsigned int max_partition_count = 0;
638 unsigned int partition_entry_size;
639 unsigned int partition_entry_array_start;
640 unsigned char *primary_gpt_header;
641 unsigned char *secondary_gpt_header;
642 unsigned int offset;
643 unsigned int partition_entry_array_size;
644 unsigned long long primary_header_location; /* address on the emmc card */
645 unsigned long long secondary_header_location; /* address on the emmc card */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700646 uint64_t device_density;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700647
Ajay Dudanib01e5062011-12-03 23:23:42 -0800648 /* Verify that passed block has a valid GPT primary header */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700649 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800650 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
651 &partition_entry_size, &header_size,
652 &max_partition_count);
653 if (ret) {
654 dprintf(CRITICAL,
655 "GPT: Primary signature invalid cannot write GPT\n");
656 goto end;
657 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700658
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700659 /* Get the density of the mmc device */
660
661 device_density = mmc_get_device_capacity();
662
Ajay Dudanib01e5062011-12-03 23:23:42 -0800663 /* Verify that passed block has a valid backup GPT HEADER */
664 partition_entry_array_size = partition_entry_size * max_partition_count;
665 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
666 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
667 }
668 offset = (2 * partition_entry_array_size);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700669 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800670 ret =
671 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
672 &partition_entry_size, &header_size,
673 &max_partition_count);
674 if (ret) {
675 dprintf(CRITICAL,
676 "GPT: Backup signature invalid cannot write GPT\n");
677 goto end;
678 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700679
Ajay Dudanib01e5062011-12-03 23:23:42 -0800680 /* Patching the primary and the backup header of the GPT table */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700681 patch_gpt(gptImage, device_density, partition_entry_array_size,
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700682 max_partition_count, partition_entry_size, block_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700683
Ajay Dudanib01e5062011-12-03 23:23:42 -0800684 /* Erasing the eMMC card before writing */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700685 ret = mmc_erase_card(0x00000000, device_density);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800686 if (ret) {
687 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
688 goto end;
689 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700690
Ajay Dudanib01e5062011-12-03 23:23:42 -0800691 /* Writing protective MBR */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700692 ret = mmc_write(0, block_size, (unsigned int *)gptImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800693 if (ret) {
694 dprintf(CRITICAL, "Failed to write Protective MBR\n");
695 goto end;
696 }
697 /* Writing the primary GPT header */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700698 primary_header_location = block_size;
699 ret = mmc_write(primary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800700 (unsigned int *)primary_gpt_header);
701 if (ret) {
702 dprintf(CRITICAL, "Failed to write GPT header\n");
703 goto end;
704 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700705
Ajay Dudanib01e5062011-12-03 23:23:42 -0800706 /* Writing the backup GPT header */
707 backup_header_lba = GET_LLWORD_FROM_BYTE
708 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700709 secondary_header_location = backup_header_lba * block_size;
710 ret = mmc_write(secondary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800711 (unsigned int *)secondary_gpt_header);
712 if (ret) {
713 dprintf(CRITICAL, "Failed to write GPT backup header\n");
714 goto end;
715 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700716
Ajay Dudanib01e5062011-12-03 23:23:42 -0800717 /* Writing the partition entries array for the primary header */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700718 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800719 ret = write_gpt_partition_array(primary_gpt_header,
720 partition_entry_array_start,
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700721 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800722 if (ret) {
723 dprintf(CRITICAL,
724 "GPT: Could not write GPT Partition entries array\n");
725 goto end;
726 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700727
Ajay Dudanib01e5062011-12-03 23:23:42 -0800728 /*Writing the partition entries array for the backup header */
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700729 partition_entry_array_start = primary_gpt_header + block_size +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800730 partition_entry_array_size;
731 ret = write_gpt_partition_array(secondary_gpt_header,
732 partition_entry_array_start,
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700733 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800734 if (ret) {
735 dprintf(CRITICAL,
736 "GPT: Could not write GPT Partition entries array\n");
737 goto end;
738 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700739
Ajay Dudanib01e5062011-12-03 23:23:42 -0800740 /* Re-read the GPT partition table */
741 dprintf(INFO, "Re-reading the GPT Partition Table\n");
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -0800742 partition_count = 0;
743 mmc_read_partition_table(0);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800744 partition_dump();
745 dprintf(CRITICAL, "GPT: Partition Table written\n");
746 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700747
Ajay Dudanib01e5062011-12-03 23:23:42 -0800748 end:
749 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700750}
751
Ajay Dudanib01e5062011-12-03 23:23:42 -0800752unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700753{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700754 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800755 unsigned int partition_type;
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700756 uint32_t block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700757
Ajay Dudanib01e5062011-12-03 23:23:42 -0800758 if (partition == 0) {
759 dprintf(CRITICAL, "NULL partition\n");
760 goto end;
761 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700762
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700763 block_size = mmc_get_device_blocksize();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800764 ret = partition_get_type(size, partition, &partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700765 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800766 goto end;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700767
Ajay Dudanib01e5062011-12-03 23:23:42 -0800768 switch (partition_type) {
769 case PARTITION_TYPE_MBR:
770 dprintf(INFO, "Writing MBR partition\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700771 ret = write_mbr(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800772 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700773
Ajay Dudanib01e5062011-12-03 23:23:42 -0800774 case PARTITION_TYPE_GPT:
775 dprintf(INFO, "Writing GPT partition\n");
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700776 ret = write_gpt(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800777 dprintf(CRITICAL, "Re-Flash all the partitions\n");
778 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700779
Ajay Dudanib01e5062011-12-03 23:23:42 -0800780 default:
781 dprintf(CRITICAL, "Invalid partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700782 ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800783 goto end;
784 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700785
Ajay Dudanib01e5062011-12-03 23:23:42 -0800786 end:
787 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700788}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800789
Kinson Chikf1a43512011-07-14 11:28:39 -0700790/*
791 * Fill name for android partition found.
792 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800793static void
794mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700795{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800796 switch (type) {
797 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
798 case MBR_MODEM_TYPE:
799 case MBR_MODEM_TYPE2:
800 /* if already assigned last name available then return */
801 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
802 return;
803 strlcpy((char *)partition_ent->name,
804 (const char *)vfat_partitions[vfat_count],
805 sizeof(partition_ent->name));
806 vfat_count++;
807 break;
808 case MBR_SBL1_TYPE:
809 memcpy(partition_ent->name, "sbl1", 4);
810 break;
811 case MBR_SBL2_TYPE:
812 memcpy(partition_ent->name, "sbl2", 4);
813 break;
814 case MBR_SBL3_TYPE:
815 memcpy(partition_ent->name, "sbl3", 4);
816 break;
817 case MBR_RPM_TYPE:
818 memcpy(partition_ent->name, "rpm", 3);
819 break;
820 case MBR_TZ_TYPE:
821 memcpy(partition_ent->name, "tz", 2);
822 break;
823 case MBR_ABOOT_TYPE:
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530824#if PLATFORM_MSM7X27A
825 memcpy(partition_ent->name, "FOTA", 4);
826#else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800827 memcpy(partition_ent->name, "aboot", 5);
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530828#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -0800829 break;
830 case MBR_BOOT_TYPE:
831 memcpy(partition_ent->name, "boot", 4);
832 break;
833 case MBR_MODEM_ST1_TYPE:
834 memcpy(partition_ent->name, "modem_st1", 9);
835 break;
836 case MBR_MODEM_ST2_TYPE:
837 memcpy(partition_ent->name, "modem_st2", 9);
838 break;
839 case MBR_EFS2_TYPE:
840 memcpy(partition_ent->name, "efs2", 4);
841 break;
842 case MBR_USERDATA_TYPE:
843 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
844 return;
845 strlcpy((char *)partition_ent->name,
846 (const char *)ext3_partitions[ext3_count],
847 sizeof(partition_ent->name));
848 ext3_count++;
849 break;
850 case MBR_RECOVERY_TYPE:
851 memcpy(partition_ent->name, "recovery", 8);
852 break;
853 case MBR_MISC_TYPE:
854 memcpy(partition_ent->name, "misc", 4);
855 break;
Neeti Desai2d6b0e42012-03-23 15:48:57 -0700856 case MBR_SSD_TYPE:
857 memcpy(partition_ent->name, "ssd", 3);
858 break;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800859 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700860}
861
862/*
863 * Find index of parition in array of partition entries
864 */
Pavel Nedev285ad922013-04-26 10:39:19 +0300865int partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700866{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800867 unsigned int input_string_length = strlen(name);
868 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700869
neetid6c38de12011-12-02 12:04:50 -0800870 if( partition_count >= NUM_PARTITIONS)
871 {
872 return INVALID_PTN;
873 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800874 for (n = 0; n < partition_count; n++) {
875 if (!memcmp
876 (name, &partition_entries[n].name, input_string_length)
877 && input_string_length ==
878 strlen((const char *)&partition_entries[n].name)) {
879 return n;
880 }
881 }
882 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700883}
884
885/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800886unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700887{
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700888 uint32_t block_size;
889
890 block_size = mmc_get_device_blocksize();
891
Ajay Dudanib01e5062011-12-03 23:23:42 -0800892 if (index == INVALID_PTN)
893 return 0;
894 else {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700895 return partition_entries[index].size * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800896 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700897}
898
899/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800900unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700901{
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700902 uint32_t block_size;
903
904 block_size = mmc_get_device_blocksize();
905
Ajay Dudanib01e5062011-12-03 23:23:42 -0800906 if (index == INVALID_PTN)
907 return 0;
908 else {
Channagoud Kadabi96c629e2013-09-10 14:21:30 -0700909 return partition_entries[index].first_lba * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800910 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700911}
912
Sundarajan Srinivasan554863f2013-12-04 17:14:37 -0800913uint8_t partition_get_lun(int index)
914{
915 return partition_entries[index].lun;
916}
917
Kinson Chikf1a43512011-07-14 11:28:39 -0700918/* Debug: Print all parsed partitions */
919void partition_dump()
920{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800921 unsigned i = 0;
922 for (i = 0; i < partition_count; i++) {
923 dprintf(SPEW,
924 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
925 i, partition_entries[i].name, partition_entries[i].size,
926 partition_entries[i].dtype,
927 partition_entries[i].first_lba,
928 partition_entries[i].last_lba);
929 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700930}
931
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700932static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800933partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700934{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800935 /* Avoid checking past end of buffer */
936 if ((TABLE_SIGNATURE + 1) > size) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700937 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800938 }
939 /* Check to see if signature exists */
940 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
941 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
942 dprintf(CRITICAL, "MBR signature does not match.\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700943 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800944 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700945 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700946}
947
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700948static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800949mbr_partition_get_type(unsigned size, unsigned char *partition,
950 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700951{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800952 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700953
Ajay Dudanib01e5062011-12-03 23:23:42 -0800954 if (size < type_offset) {
955 goto end;
956 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700957
Ajay Dudanib01e5062011-12-03 23:23:42 -0800958 *partition_type = partition[type_offset];
959 end:
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700960 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700961}
962
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700963static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800964partition_get_type(unsigned size, unsigned char *partition,
965 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700966{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700967 unsigned int ret = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700968
Ajay Dudanib01e5062011-12-03 23:23:42 -0800969 /*
970 * If the block contains the MBR signature, then it's likely either
971 * MBR or MBR with protective type (GPT). If the MBR signature is
972 * not there, then it could be the GPT backup.
973 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700974
Ajay Dudanib01e5062011-12-03 23:23:42 -0800975 /* First check the MBR signature */
976 ret = partition_verify_mbr_signature(size, partition);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700977 if (!ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800978 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -0700979
Ajay Dudanib01e5062011-12-03 23:23:42 -0800980 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
981 ret =
982 mbr_partition_get_type(size, partition,
983 &mbr_partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700984 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800985 dprintf(CRITICAL, "Cannot get TYPE of partition");
986 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
987 *partition_type = PARTITION_TYPE_GPT;
988 } else {
989 *partition_type = PARTITION_TYPE_MBR;
990 }
991 } else {
992 /*
993 * This could be the GPT backup. Make that assumption for now.
994 * Anybody who treats the block as GPT backup should check the
995 * signature.
996 */
997 *partition_type = PARTITION_TYPE_GPT_BACKUP;
998 }
999 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -07001000}
Kinson Chik4d7444f2011-09-13 15:48:51 -07001001
1002/*
1003 * Parse the gpt header and get the required header fields
1004 * Return 0 on valid signature
1005 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -07001006static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -08001007partition_parse_gpt_header(unsigned char *buffer,
1008 unsigned long long *first_usable_lba,
1009 unsigned int *partition_entry_size,
1010 unsigned int *header_size,
1011 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -07001012{
Ajay Dudanib01e5062011-12-03 23:23:42 -08001013 /* Check GPT Signature */
1014 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
1015 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
1016 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001017
Ajay Dudanib01e5062011-12-03 23:23:42 -08001018 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
1019 *first_usable_lba =
1020 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
1021 *max_partition_count =
1022 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
1023 *partition_entry_size =
1024 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -07001025
Ajay Dudanib01e5062011-12-03 23:23:42 -08001026 return 0;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001027}
Pavel Nedevb5ba62d2013-07-22 11:57:41 +03001028
1029bool partition_gpt_exists()
1030{
1031 return (gpt_partitions_exist != 0);
1032}