blob: 6facb9340d6958f96156a1ae342e8ea0236610ab [file] [log] [blame]
Channagoud Kadabif73aa292013-01-31 16:55:20 -08001/* Copyright (c) 2011-2013, 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
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070034static uint32_t mmc_boot_read_gpt(uint32_t block_size);
35static uint32_t mmc_boot_read_mbr(uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070036static void mbr_fill_name(struct partition_entry *partition_ent,
37 uint32_t type);
38static uint32_t partition_verify_mbr_signature(uint32_t size,
39 uint8_t *buffer);
40static uint32_t mbr_partition_get_type(uint32_t size, uint8_t *partition,
41 uint32_t *partition_type);
42
43static uint32_t partition_get_type(uint32_t size, uint8_t *partition,
44 uint32_t *partition_type);
45static uint32_t partition_parse_gpt_header(uint8_t *buffer,
46 uint64_t *first_usable_lba,
47 uint32_t *partition_entry_size,
48 uint32_t *header_size,
49 uint32_t *max_partition_count);
50
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070051static uint32_t write_mbr(uint32_t, uint8_t *mbrImage, uint32_t block_size);
52static uint32_t write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070053
Ajay Dudanib01e5062011-12-03 23:23:42 -080054char *ext3_partitions[] =
55 { "system", "userdata", "persist", "cache", "tombstones" };
56char *vfat_partitions[] = { "modem", "mdm", "NONE" };
57
Kinson Chikf1a43512011-07-14 11:28:39 -070058unsigned int ext3_count = 0;
59unsigned int vfat_count = 0;
60
Channagoud Kadabie9b94022013-11-12 13:49:41 -080061struct partition_entry *partition_entries;
Pavel Nedevb5ba62d2013-07-22 11:57:41 +030062static unsigned gpt_partitions_exist = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -070063unsigned partition_count = 0;
64
Channagoud Kadabi0e332852013-04-19 12:55:53 -070065unsigned int partition_read_table()
Kinson Chikf1a43512011-07-14 11:28:39 -070066{
Ajay Dudanib01e5062011-12-03 23:23:42 -080067 unsigned int ret;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070068 uint32_t block_size;
69
70 block_size = mmc_get_device_blocksize();
Kinson Chikf1a43512011-07-14 11:28:39 -070071
Channagoud Kadabie9b94022013-11-12 13:49:41 -080072 /* Allocate partition entries array */
73 partition_entries = (struct partition_entry *) calloc(NUM_PARTITIONS, sizeof(struct partition_entry));
74 ASSERT(partition_entries);
75
Ajay Dudanib01e5062011-12-03 23:23:42 -080076 /* Read MBR of the card */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070077 ret = mmc_boot_read_mbr(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070078 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -080079 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -070080 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -080081 }
Kinson Chikf1a43512011-07-14 11:28:39 -070082
Ajay Dudanib01e5062011-12-03 23:23:42 -080083 /* Read GPT of the card if exist */
84 if (gpt_partitions_exist) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070085 ret = mmc_boot_read_gpt(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070086 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -080087 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -070088 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -080089 }
90 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -070091 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -070092}
93
94/*
95 * Read MBR from MMC card and fill partition table.
96 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070097static unsigned int mmc_boot_read_mbr(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -070098{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070099 uint8_t *buffer = NULL;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800100 unsigned int dtype;
101 unsigned int dfirstsec;
102 unsigned int EBR_first_sec;
103 unsigned int EBR_current_sec;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700104 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800105 int idx, i;
Kinson Chikf1a43512011-07-14 11:28:39 -0700106
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700107 buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
108
109 if (!buffer)
110 {
111 dprintf(CRITICAL, "Error allocating memory while reading partition table\n");
112 ret = -1;
113 goto end;
114 }
115
Ajay Dudanib01e5062011-12-03 23:23:42 -0800116 /* Print out the MBR first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700117 ret = mmc_read(0, (unsigned int *)buffer, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800118 if (ret) {
119 dprintf(CRITICAL, "Could not read partition from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700120 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800121 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700122
Ajay Dudanib01e5062011-12-03 23:23:42 -0800123 /* Check to see if signature exists */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700124 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800125 if (ret) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700126 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800127 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700128
Ajay Dudanib01e5062011-12-03 23:23:42 -0800129 /*
130 * Process each of the four partitions in the MBR by reading the table
131 * information into our mbr table.
132 */
133 partition_count = 0;
134 idx = TABLE_ENTRY_0;
135 for (i = 0; i < 4; i++) {
136 /* Type 0xEE indicates end of MBR and GPT partitions exist */
137 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
138 if (dtype == MBR_PROTECTED_TYPE) {
139 gpt_partitions_exist = 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700140 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800141 }
142 partition_entries[partition_count].dtype = dtype;
143 partition_entries[partition_count].attribute_flag =
144 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
145 partition_entries[partition_count].first_lba =
146 GET_LWORD_FROM_BYTE(&buffer[idx +
147 i * TABLE_ENTRY_SIZE +
148 OFFSET_FIRST_SEC]);
149 partition_entries[partition_count].size =
150 GET_LWORD_FROM_BYTE(&buffer[idx +
151 i * TABLE_ENTRY_SIZE +
152 OFFSET_SIZE]);
153 dfirstsec = partition_entries[partition_count].first_lba;
154 mbr_fill_name(&partition_entries[partition_count],
155 partition_entries[partition_count].dtype);
156 partition_count++;
157 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700158 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800159 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700160
Ajay Dudanib01e5062011-12-03 23:23:42 -0800161 /* See if the last partition is EBR, if not, parsing is done */
162 if (dtype != MBR_EBR_TYPE) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700163 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800164 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700165
Ajay Dudanib01e5062011-12-03 23:23:42 -0800166 EBR_first_sec = dfirstsec;
167 EBR_current_sec = dfirstsec;
Kinson Chikf1a43512011-07-14 11:28:39 -0700168
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700169 ret = mmc_read((EBR_first_sec * block_size), (unsigned int *)buffer, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700170 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700171 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700172
Ajay Dudanib01e5062011-12-03 23:23:42 -0800173 /* Loop to parse the EBR */
174 for (i = 0;; i++) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700175 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800176 if (ret) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700177 ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800178 break;
179 }
180 partition_entries[partition_count].attribute_flag =
181 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
182 partition_entries[partition_count].dtype =
183 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
184 partition_entries[partition_count].first_lba =
185 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
186 OFFSET_FIRST_SEC]) +
187 EBR_current_sec;
188 partition_entries[partition_count].size =
189 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
190 mbr_fill_name(&(partition_entries[partition_count]),
191 partition_entries[partition_count].dtype);
192 partition_count++;
193 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700194 goto end;
Kinson Chikf1a43512011-07-14 11:28:39 -0700195
Ajay Dudanib01e5062011-12-03 23:23:42 -0800196 dfirstsec =
197 GET_LWORD_FROM_BYTE(&buffer
198 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
199 if (dfirstsec == 0) {
200 /* Getting to the end of the EBR tables */
201 break;
202 }
203 /* More EBR to follow - read in the next EBR sector */
204 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
205 + dfirstsec);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700206 ret = mmc_read(((EBR_first_sec + dfirstsec) * block_size),(unsigned int *)buffer,
207 block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700208 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700209 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700210
Ajay Dudanib01e5062011-12-03 23:23:42 -0800211 EBR_current_sec = EBR_first_sec + dfirstsec;
212 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700213end:
214 if (buffer)
215 free(buffer);
216
Ajay Dudanib01e5062011-12-03 23:23:42 -0800217 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700218}
Kinson Chik66552a82011-03-29 15:59:06 -0700219
220/*
221 * Read GPT from MMC and fill partition table
222 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700223static unsigned int mmc_boot_read_gpt(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700224{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700225 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800226 unsigned int header_size;
227 unsigned long long first_usable_lba;
228 unsigned long long backup_header_lba;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700229 unsigned long long card_size_sec;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800230 unsigned int max_partition_count = 0;
231 unsigned int partition_entry_size;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700232 unsigned int i = 0; /* Counter for each block */
233 unsigned int j = 0; /* Counter for each entry in a block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800234 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
235 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
236 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700237 unsigned long long partition_0;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700238 uint64_t device_density;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700239 uint8_t *data = NULL;
240 uint32_t part_entry_cnt = block_size / ENTRY_SIZE;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700241
Ajay Dudanib01e5062011-12-03 23:23:42 -0800242 partition_count = 0;
Kinson Chik66552a82011-03-29 15:59:06 -0700243
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700244 /* Get the density of the mmc device */
245
246 device_density = mmc_get_device_capacity();
247
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700248 data = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
249 if (!data)
250 {
251 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
252 ret = -1;
253 goto end;
254 }
255
Ajay Dudanib01e5062011-12-03 23:23:42 -0800256 /* Print out the GPT first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700257 ret = mmc_read(block_size, (unsigned int *)data, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700258 if (ret)
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700259 {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800260 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700261 goto end;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700262 }
Kinson Chik66552a82011-03-29 15:59:06 -0700263
Ajay Dudanib01e5062011-12-03 23:23:42 -0800264 ret = partition_parse_gpt_header(data, &first_usable_lba,
265 &partition_entry_size, &header_size,
266 &max_partition_count);
267 if (ret) {
268 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700269
Ajay Dudanib01e5062011-12-03 23:23:42 -0800270 /* Check the backup gpt */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700271
272 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700273 card_size_sec = (device_density) / block_size;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700274 ASSERT (card_size_sec > 0);
275
276 backup_header_lba = card_size_sec - 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700277 ret = mmc_read((backup_header_lba * block_size), (unsigned int *)data,
278 block_size);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700279
Ajay Dudanib01e5062011-12-03 23:23:42 -0800280 if (ret) {
281 dprintf(CRITICAL,
282 "GPT: Could not read backup gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700283 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800284 }
Kinson Chik4d7444f2011-09-13 15:48:51 -0700285
Ajay Dudanib01e5062011-12-03 23:23:42 -0800286 ret = partition_parse_gpt_header(data, &first_usable_lba,
287 &partition_entry_size,
288 &header_size,
289 &max_partition_count);
290 if (ret) {
291 dprintf(CRITICAL,
292 "GPT: Primary and backup signatures invalid\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700293 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800294 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800295 }
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700296 partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800297 /* Read GPT Entries */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700298 for (i = 0; i < (ROUNDUP(max_partition_count, part_entry_cnt)) / part_entry_cnt; i++) {
neetid6c38de12011-12-02 12:04:50 -0800299 ASSERT(partition_count < NUM_PARTITIONS);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700300 ret = mmc_read((partition_0 * block_size) + (i * block_size),
301 (uint32_t *) data, block_size);
Kinson Chik66552a82011-03-29 15:59:06 -0700302
Ajay Dudanib01e5062011-12-03 23:23:42 -0800303 if (ret) {
304 dprintf(CRITICAL,
305 "GPT: mmc read card failed reading partition entries.\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700306 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800307 }
Kinson Chik66552a82011-03-29 15:59:06 -0700308
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700309 for (j = 0; j < part_entry_cnt; j++) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800310 memcpy(&(partition_entries[partition_count].type_guid),
311 &data[(j * partition_entry_size)],
312 PARTITION_TYPE_GUID_SIZE);
313 if (partition_entries[partition_count].type_guid[0] ==
314 0x00
315 && partition_entries[partition_count].
316 type_guid[1] == 0x00) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700317 i = ROUNDUP(max_partition_count, part_entry_cnt);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800318 break;
319 }
320 memcpy(&
321 (partition_entries[partition_count].
322 unique_partition_guid),
323 &data[(j * partition_entry_size) +
324 UNIQUE_GUID_OFFSET],
325 UNIQUE_PARTITION_GUID_SIZE);
326 partition_entries[partition_count].first_lba =
327 GET_LLWORD_FROM_BYTE(&data
328 [(j * partition_entry_size) +
329 FIRST_LBA_OFFSET]);
330 partition_entries[partition_count].last_lba =
331 GET_LLWORD_FROM_BYTE(&data
332 [(j * partition_entry_size) +
333 LAST_LBA_OFFSET]);
334 partition_entries[partition_count].size =
335 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700336 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800337 partition_entries[partition_count].attribute_flag =
338 GET_LLWORD_FROM_BYTE(&data
339 [(j * partition_entry_size) +
340 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700341
Ajay Dudanib01e5062011-12-03 23:23:42 -0800342 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
343 memcpy(UTF16_name, &data[(j * partition_entry_size) +
344 PARTITION_NAME_OFFSET],
345 MAX_GPT_NAME_SIZE);
346 /*
347 * Currently partition names in *.xml are UTF-8 and lowercase
348 * Only supporting english for now so removing 2nd byte of UTF-16
349 */
350 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
351 partition_entries[partition_count].name[n] =
352 UTF16_name[n * 2];
353 }
354 partition_count++;
355 }
356 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700357end:
358 if (data)
359 free(data);
360
Ajay Dudanib01e5062011-12-03 23:23:42 -0800361 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700362}
363
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700364static unsigned int write_mbr_in_blocks(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700365{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800366 unsigned int dtype;
367 unsigned int dfirstsec;
368 unsigned int ebrSectorOffset;
369 unsigned char *ebrImage;
370 unsigned char *lastAddress;
371 int idx, i;
372 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700373
Ajay Dudanib01e5062011-12-03 23:23:42 -0800374 /* Write the first block */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700375 ret = mmc_write(0, block_size, (unsigned int *)mbrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800376 if (ret) {
377 dprintf(CRITICAL, "Failed to write mbr partition\n");
378 goto end;
379 }
380 dprintf(SPEW, "write of first MBR block ok\n");
381 /*
382 Loop through the MBR table to see if there is an EBR.
383 If found, then figure out where to write the first EBR
384 */
385 idx = TABLE_ENTRY_0;
386 for (i = 0; i < 4; i++) {
387 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
388 if (MBR_EBR_TYPE == dtype) {
389 dprintf(SPEW, "EBR found.\n");
390 break;
391 }
392 }
393 if (MBR_EBR_TYPE != dtype) {
394 dprintf(SPEW, "No EBR in this image\n");
395 goto end;
396 }
397 /* EBR exists. Write each EBR block to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700398 ebrImage = mbrImage + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800399 ebrSectorOffset =
400 GET_LWORD_FROM_BYTE(&mbrImage
401 [idx + i * TABLE_ENTRY_SIZE +
402 OFFSET_FIRST_SEC]);
403 dfirstsec = 0;
404 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
405 lastAddress = mbrImage + size;
406 while (ebrImage < lastAddress) {
407 dprintf(SPEW, "writing to 0x%X\n",
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700408 (ebrSectorOffset + dfirstsec) * block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800409 ret =
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700410 mmc_write((ebrSectorOffset + dfirstsec) * block_size,
411 block_size, (unsigned int *)ebrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800412 if (ret) {
413 dprintf(CRITICAL,
414 "Failed to write EBR block to sector 0x%X\n",
415 dfirstsec);
416 goto end;
417 }
418 dfirstsec =
419 GET_LWORD_FROM_BYTE(&ebrImage
420 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700421 ebrImage += block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800422 }
423 dprintf(INFO, "MBR written to mmc successfully\n");
424 end:
425 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700426}
427
428/* Write the MBR/EBR to the MMC. */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700429static unsigned int write_mbr(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700430{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800431 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700432
Ajay Dudanib01e5062011-12-03 23:23:42 -0800433 /* Verify that passed in block is a valid MBR */
434 ret = partition_verify_mbr_signature(size, mbrImage);
435 if (ret) {
436 goto end;
437 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700438
Ajay Dudanib01e5062011-12-03 23:23:42 -0800439 /* Write the MBR/EBR to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700440 ret = write_mbr_in_blocks(size, mbrImage, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800441 if (ret) {
442 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
443 goto end;
444 }
445 /* Re-read the MBR partition into mbr table */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700446 ret = mmc_boot_read_mbr(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800447 if (ret) {
448 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
449 goto end;
450 }
451 partition_dump();
452 end:
453 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700454}
455
456/*
457 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
458*/
459int reflect(int data, int len)
460{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800461 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700462
Ajay Dudanib01e5062011-12-03 23:23:42 -0800463 for (int i = 0; i < len; i++) {
464 if (data & 0x1) {
465 ref |= (1 << ((len - 1) - i));
466 }
467 data = (data >> 1);
468 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700469
Ajay Dudanib01e5062011-12-03 23:23:42 -0800470 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700471}
472
473/*
474* Function to calculate the CRC32
475*/
476unsigned int calculate_crc32(unsigned char *buffer, int len)
477{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800478 int byte_length = 8; /*length of unit (i.e. byte) */
479 int msb = 0;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700480 int polynomial = 0x04C11DB7; /* IEEE 32bit polynomial */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800481 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
482 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
483 int regs_msb = 0;
484 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700485
Ajay Dudanib01e5062011-12-03 23:23:42 -0800486 for (int i = 0; i < len; i++) {
487 int data_byte = buffer[i];
488 data_byte = reflect(data_byte, 8);
489 for (int j = 0; j < byte_length; j++) {
490 msb = data_byte >> (byte_length - 1); /* get MSB */
491 msb &= 1; /* ensure just 1 bit */
492 regs_msb = (regs >> 31) & 1; /* MSB of regs */
493 regs = regs << 1; /* shift regs for CRC-CCITT */
494 if (regs_msb ^ msb) { /* MSB is a 1 */
495 regs = regs ^ polynomial; /* XOR with generator poly */
496 }
497 regs = regs & regs_mask; /* Mask off excess upper bits */
498 data_byte <<= 1; /* get to next bit */
499 }
500 }
501 regs = regs & regs_mask;
502 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700503
Ajay Dudanib01e5062011-12-03 23:23:42 -0800504 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700505}
506
507/*
508 * Write the GPT Partition Entry Array to the MMC.
509 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800510static unsigned int
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700511write_gpt_partition_array(uint8_t *header,
512 uint32_t partition_array_start,
513 uint32_t array_size,
514 uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700515{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700516 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800517 unsigned long long partition_entry_lba;
518 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700519
Ajay Dudanib01e5062011-12-03 23:23:42 -0800520 partition_entry_lba =
521 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700522 partition_entry_array_start_location = partition_entry_lba * block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700523
Ajay Dudanib01e5062011-12-03 23:23:42 -0800524 ret = mmc_write(partition_entry_array_start_location, array_size,
525 (unsigned int *)partition_array_start);
526 if (ret) {
527 dprintf(CRITICAL,
528 "GPT: FAILED to write the partition entry array\n");
529 goto end;
530 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700531
Ajay Dudanib01e5062011-12-03 23:23:42 -0800532 end:
533 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700534}
535
Ajay Dudanib01e5062011-12-03 23:23:42 -0800536static void
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700537patch_gpt(uint8_t *gptImage, uint64_t density, uint32_t array_size,
538 uint32_t max_part_count, uint32_t part_entry_size, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700539{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800540 unsigned int partition_entry_array_start;
541 unsigned char *primary_gpt_header;
542 unsigned char *secondary_gpt_header;
543 unsigned int offset;
544 unsigned long long card_size_sec;
545 int total_part = 0;
546 unsigned int last_part_offset;
547 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700548
Ajay Dudanib01e5062011-12-03 23:23:42 -0800549 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700550 card_size_sec = (density) / block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800551 /* Working around cap at 4GB */
552 if (card_size_sec == 0) {
553 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
554 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700555
Ajay Dudanib01e5062011-12-03 23:23:42 -0800556 /* Patching primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700557 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800558 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
559 ((long long)(card_size_sec - 1)));
560 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
561 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700562
Ajay Dudanib01e5062011-12-03 23:23:42 -0800563 /* Patching backup GPT */
564 offset = (2 * array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700565 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800566 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
567 ((long long)(card_size_sec - 1)));
568 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
569 ((long long)(card_size_sec - 34)));
570 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
571 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700572
Ajay Dudanib01e5062011-12-03 23:23:42 -0800573 /* Find last partition */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700574 while (*(primary_gpt_header + block_size + total_part * ENTRY_SIZE) !=
Ajay Dudanib01e5062011-12-03 23:23:42 -0800575 0) {
576 total_part++;
577 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700578
Ajay Dudanib01e5062011-12-03 23:23:42 -0800579 /* Patching last partition */
580 last_part_offset =
581 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700582 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800583 (long long)(card_size_sec - 34));
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700584 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800585 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700586
Ajay Dudanib01e5062011-12-03 23:23:42 -0800587 /* Updating CRC of the Partition entry array in both headers */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700588 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800589 crc_value = calculate_crc32(partition_entry_array_start,
590 max_part_count * part_entry_size);
591 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700592
Ajay Dudanib01e5062011-12-03 23:23:42 -0800593 crc_value = calculate_crc32(partition_entry_array_start + array_size,
594 max_part_count * part_entry_size);
595 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700596
Ajay Dudanib01e5062011-12-03 23:23:42 -0800597 /* Clearing CRC fields to calculate */
598 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
599 crc_value = calculate_crc32(primary_gpt_header, 92);
600 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700601
Ajay Dudanib01e5062011-12-03 23:23:42 -0800602 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
603 crc_value = (calculate_crc32(secondary_gpt_header, 92));
604 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700605
606}
607
608/*
609 * Write the GPT to the MMC.
610 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700611static unsigned int write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700612{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700613 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800614 unsigned int header_size;
615 unsigned long long first_usable_lba;
616 unsigned long long backup_header_lba;
617 unsigned int max_partition_count = 0;
618 unsigned int partition_entry_size;
619 unsigned int partition_entry_array_start;
620 unsigned char *primary_gpt_header;
621 unsigned char *secondary_gpt_header;
622 unsigned int offset;
623 unsigned int partition_entry_array_size;
624 unsigned long long primary_header_location; /* address on the emmc card */
625 unsigned long long secondary_header_location; /* address on the emmc card */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700626 uint64_t device_density;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700627
Ajay Dudanib01e5062011-12-03 23:23:42 -0800628 /* Verify that passed block has a valid GPT primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700629 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800630 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
631 &partition_entry_size, &header_size,
632 &max_partition_count);
633 if (ret) {
634 dprintf(CRITICAL,
635 "GPT: Primary signature invalid cannot write GPT\n");
636 goto end;
637 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700638
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700639 /* Get the density of the mmc device */
640
641 device_density = mmc_get_device_capacity();
642
Ajay Dudanib01e5062011-12-03 23:23:42 -0800643 /* Verify that passed block has a valid backup GPT HEADER */
644 partition_entry_array_size = partition_entry_size * max_partition_count;
645 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
646 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
647 }
648 offset = (2 * partition_entry_array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700649 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800650 ret =
651 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
652 &partition_entry_size, &header_size,
653 &max_partition_count);
654 if (ret) {
655 dprintf(CRITICAL,
656 "GPT: Backup signature invalid cannot write GPT\n");
657 goto end;
658 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700659
Ajay Dudanib01e5062011-12-03 23:23:42 -0800660 /* Patching the primary and the backup header of the GPT table */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700661 patch_gpt(gptImage, device_density, partition_entry_array_size,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700662 max_partition_count, partition_entry_size, block_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700663
Ajay Dudanib01e5062011-12-03 23:23:42 -0800664 /* Erasing the eMMC card before writing */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700665 ret = mmc_erase_card(0x00000000, device_density);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800666 if (ret) {
667 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
668 goto end;
669 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700670
Ajay Dudanib01e5062011-12-03 23:23:42 -0800671 /* Writing protective MBR */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700672 ret = mmc_write(0, block_size, (unsigned int *)gptImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800673 if (ret) {
674 dprintf(CRITICAL, "Failed to write Protective MBR\n");
675 goto end;
676 }
677 /* Writing the primary GPT header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700678 primary_header_location = block_size;
679 ret = mmc_write(primary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800680 (unsigned int *)primary_gpt_header);
681 if (ret) {
682 dprintf(CRITICAL, "Failed to write GPT header\n");
683 goto end;
684 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700685
Ajay Dudanib01e5062011-12-03 23:23:42 -0800686 /* Writing the backup GPT header */
687 backup_header_lba = GET_LLWORD_FROM_BYTE
688 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700689 secondary_header_location = backup_header_lba * block_size;
690 ret = mmc_write(secondary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800691 (unsigned int *)secondary_gpt_header);
692 if (ret) {
693 dprintf(CRITICAL, "Failed to write GPT backup header\n");
694 goto end;
695 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700696
Ajay Dudanib01e5062011-12-03 23:23:42 -0800697 /* Writing the partition entries array for the primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700698 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800699 ret = write_gpt_partition_array(primary_gpt_header,
700 partition_entry_array_start,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700701 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800702 if (ret) {
703 dprintf(CRITICAL,
704 "GPT: Could not write GPT Partition entries array\n");
705 goto end;
706 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700707
Ajay Dudanib01e5062011-12-03 23:23:42 -0800708 /*Writing the partition entries array for the backup header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700709 partition_entry_array_start = primary_gpt_header + block_size +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800710 partition_entry_array_size;
711 ret = write_gpt_partition_array(secondary_gpt_header,
712 partition_entry_array_start,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700713 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800714 if (ret) {
715 dprintf(CRITICAL,
716 "GPT: Could not write GPT Partition entries array\n");
717 goto end;
718 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700719
Ajay Dudanib01e5062011-12-03 23:23:42 -0800720 /* Re-read the GPT partition table */
721 dprintf(INFO, "Re-reading the GPT Partition Table\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700722 ret = mmc_boot_read_gpt(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800723 if (ret) {
724 dprintf(CRITICAL,
725 "GPT: Failure to re- read the GPT Partition table\n");
726 goto end;
727 }
728 partition_dump();
729 dprintf(CRITICAL, "GPT: Partition Table written\n");
730 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700731
Ajay Dudanib01e5062011-12-03 23:23:42 -0800732 end:
733 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700734}
735
Ajay Dudanib01e5062011-12-03 23:23:42 -0800736unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700737{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700738 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800739 unsigned int partition_type;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700740 uint32_t block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700741
Ajay Dudanib01e5062011-12-03 23:23:42 -0800742 if (partition == 0) {
743 dprintf(CRITICAL, "NULL partition\n");
744 goto end;
745 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700746
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700747 block_size = mmc_get_device_blocksize();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800748 ret = partition_get_type(size, partition, &partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700749 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800750 goto end;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700751
Ajay Dudanib01e5062011-12-03 23:23:42 -0800752 switch (partition_type) {
753 case PARTITION_TYPE_MBR:
754 dprintf(INFO, "Writing MBR partition\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700755 ret = write_mbr(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800756 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700757
Ajay Dudanib01e5062011-12-03 23:23:42 -0800758 case PARTITION_TYPE_GPT:
759 dprintf(INFO, "Writing GPT partition\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700760 ret = write_gpt(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800761 dprintf(CRITICAL, "Re-Flash all the partitions\n");
762 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700763
Ajay Dudanib01e5062011-12-03 23:23:42 -0800764 default:
765 dprintf(CRITICAL, "Invalid partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700766 ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800767 goto end;
768 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700769
Ajay Dudanib01e5062011-12-03 23:23:42 -0800770 end:
771 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700772}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800773
Kinson Chikf1a43512011-07-14 11:28:39 -0700774/*
775 * Fill name for android partition found.
776 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800777static void
778mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700779{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800780 switch (type) {
781 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
782 case MBR_MODEM_TYPE:
783 case MBR_MODEM_TYPE2:
784 /* if already assigned last name available then return */
785 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
786 return;
787 strlcpy((char *)partition_ent->name,
788 (const char *)vfat_partitions[vfat_count],
789 sizeof(partition_ent->name));
790 vfat_count++;
791 break;
792 case MBR_SBL1_TYPE:
793 memcpy(partition_ent->name, "sbl1", 4);
794 break;
795 case MBR_SBL2_TYPE:
796 memcpy(partition_ent->name, "sbl2", 4);
797 break;
798 case MBR_SBL3_TYPE:
799 memcpy(partition_ent->name, "sbl3", 4);
800 break;
801 case MBR_RPM_TYPE:
802 memcpy(partition_ent->name, "rpm", 3);
803 break;
804 case MBR_TZ_TYPE:
805 memcpy(partition_ent->name, "tz", 2);
806 break;
807 case MBR_ABOOT_TYPE:
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530808#if PLATFORM_MSM7X27A
809 memcpy(partition_ent->name, "FOTA", 4);
810#else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800811 memcpy(partition_ent->name, "aboot", 5);
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530812#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -0800813 break;
814 case MBR_BOOT_TYPE:
815 memcpy(partition_ent->name, "boot", 4);
816 break;
817 case MBR_MODEM_ST1_TYPE:
818 memcpy(partition_ent->name, "modem_st1", 9);
819 break;
820 case MBR_MODEM_ST2_TYPE:
821 memcpy(partition_ent->name, "modem_st2", 9);
822 break;
823 case MBR_EFS2_TYPE:
824 memcpy(partition_ent->name, "efs2", 4);
825 break;
826 case MBR_USERDATA_TYPE:
827 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
828 return;
829 strlcpy((char *)partition_ent->name,
830 (const char *)ext3_partitions[ext3_count],
831 sizeof(partition_ent->name));
832 ext3_count++;
833 break;
834 case MBR_RECOVERY_TYPE:
835 memcpy(partition_ent->name, "recovery", 8);
836 break;
837 case MBR_MISC_TYPE:
838 memcpy(partition_ent->name, "misc", 4);
839 break;
Neeti Desai2d6b0e42012-03-23 15:48:57 -0700840 case MBR_SSD_TYPE:
841 memcpy(partition_ent->name, "ssd", 3);
842 break;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800843 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700844}
845
846/*
847 * Find index of parition in array of partition entries
848 */
Pavel Nedev285ad922013-04-26 10:39:19 +0300849int partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700850{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800851 unsigned int input_string_length = strlen(name);
852 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700853
neetid6c38de12011-12-02 12:04:50 -0800854 if( partition_count >= NUM_PARTITIONS)
855 {
856 return INVALID_PTN;
857 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800858 for (n = 0; n < partition_count; n++) {
859 if (!memcmp
860 (name, &partition_entries[n].name, input_string_length)
861 && input_string_length ==
862 strlen((const char *)&partition_entries[n].name)) {
863 return n;
864 }
865 }
866 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700867}
868
869/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800870unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700871{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700872 uint32_t block_size;
873
874 block_size = mmc_get_device_blocksize();
875
Ajay Dudanib01e5062011-12-03 23:23:42 -0800876 if (index == INVALID_PTN)
877 return 0;
878 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700879 return partition_entries[index].size * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800880 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700881}
882
883/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800884unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700885{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700886 uint32_t block_size;
887
888 block_size = mmc_get_device_blocksize();
889
Ajay Dudanib01e5062011-12-03 23:23:42 -0800890 if (index == INVALID_PTN)
891 return 0;
892 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700893 return partition_entries[index].first_lba * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800894 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700895}
896
897/* Debug: Print all parsed partitions */
898void partition_dump()
899{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800900 unsigned i = 0;
901 for (i = 0; i < partition_count; i++) {
902 dprintf(SPEW,
903 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
904 i, partition_entries[i].name, partition_entries[i].size,
905 partition_entries[i].dtype,
906 partition_entries[i].first_lba,
907 partition_entries[i].last_lba);
908 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700909}
910
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700911static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800912partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700913{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800914 /* Avoid checking past end of buffer */
915 if ((TABLE_SIGNATURE + 1) > size) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700916 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800917 }
918 /* Check to see if signature exists */
919 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
920 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
921 dprintf(CRITICAL, "MBR signature does not match.\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700922 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800923 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700924 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700925}
926
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700927static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800928mbr_partition_get_type(unsigned size, unsigned char *partition,
929 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700930{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800931 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700932
Ajay Dudanib01e5062011-12-03 23:23:42 -0800933 if (size < type_offset) {
934 goto end;
935 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700936
Ajay Dudanib01e5062011-12-03 23:23:42 -0800937 *partition_type = partition[type_offset];
938 end:
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700939 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700940}
941
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700942static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800943partition_get_type(unsigned size, unsigned char *partition,
944 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700945{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700946 unsigned int ret = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700947
Ajay Dudanib01e5062011-12-03 23:23:42 -0800948 /*
949 * If the block contains the MBR signature, then it's likely either
950 * MBR or MBR with protective type (GPT). If the MBR signature is
951 * not there, then it could be the GPT backup.
952 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700953
Ajay Dudanib01e5062011-12-03 23:23:42 -0800954 /* First check the MBR signature */
955 ret = partition_verify_mbr_signature(size, partition);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700956 if (!ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800957 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -0700958
Ajay Dudanib01e5062011-12-03 23:23:42 -0800959 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
960 ret =
961 mbr_partition_get_type(size, partition,
962 &mbr_partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700963 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800964 dprintf(CRITICAL, "Cannot get TYPE of partition");
965 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
966 *partition_type = PARTITION_TYPE_GPT;
967 } else {
968 *partition_type = PARTITION_TYPE_MBR;
969 }
970 } else {
971 /*
972 * This could be the GPT backup. Make that assumption for now.
973 * Anybody who treats the block as GPT backup should check the
974 * signature.
975 */
976 *partition_type = PARTITION_TYPE_GPT_BACKUP;
977 }
978 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700979}
Kinson Chik4d7444f2011-09-13 15:48:51 -0700980
981/*
982 * Parse the gpt header and get the required header fields
983 * Return 0 on valid signature
984 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700985static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800986partition_parse_gpt_header(unsigned char *buffer,
987 unsigned long long *first_usable_lba,
988 unsigned int *partition_entry_size,
989 unsigned int *header_size,
990 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -0700991{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800992 /* Check GPT Signature */
993 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
994 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
995 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -0700996
Ajay Dudanib01e5062011-12-03 23:23:42 -0800997 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
998 *first_usable_lba =
999 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
1000 *max_partition_count =
1001 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
1002 *partition_entry_size =
1003 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -07001004
Ajay Dudanib01e5062011-12-03 23:23:42 -08001005 return 0;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001006}
Pavel Nedevb5ba62d2013-07-22 11:57:41 +03001007
1008bool partition_gpt_exists()
1009{
1010 return (gpt_partitions_exist != 0);
1011}