blob: e2d548e9cf821706da19edb2d0971051ccaf0f0d [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
61struct partition_entry partition_entries[NUM_PARTITIONS];
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
Ajay Dudanib01e5062011-12-03 23:23:42 -080072 /* Read MBR of the card */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070073 ret = mmc_boot_read_mbr(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070074 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -080075 dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -070076 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -080077 }
Kinson Chikf1a43512011-07-14 11:28:39 -070078
Ajay Dudanib01e5062011-12-03 23:23:42 -080079 /* Read GPT of the card if exist */
80 if (gpt_partitions_exist) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070081 ret = mmc_boot_read_gpt(block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -070082 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -080083 dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -070084 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -080085 }
86 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -070087 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -070088}
89
90/*
91 * Read MBR from MMC card and fill partition table.
92 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070093static unsigned int mmc_boot_read_mbr(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -070094{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -070095 uint8_t *buffer = NULL;
Ajay Dudanib01e5062011-12-03 23:23:42 -080096 unsigned int dtype;
97 unsigned int dfirstsec;
98 unsigned int EBR_first_sec;
99 unsigned int EBR_current_sec;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700100 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800101 int idx, i;
Kinson Chikf1a43512011-07-14 11:28:39 -0700102
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700103 buffer = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
104
105 if (!buffer)
106 {
107 dprintf(CRITICAL, "Error allocating memory while reading partition table\n");
108 ret = -1;
109 goto end;
110 }
111
Ajay Dudanib01e5062011-12-03 23:23:42 -0800112 /* Print out the MBR first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700113 ret = mmc_read(0, (unsigned int *)buffer, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800114 if (ret) {
115 dprintf(CRITICAL, "Could not read partition from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700116 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800117 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700118
Ajay Dudanib01e5062011-12-03 23:23:42 -0800119 /* Check to see if signature exists */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700120 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800121 if (ret) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700122 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800123 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700124
Ajay Dudanib01e5062011-12-03 23:23:42 -0800125 /*
126 * Process each of the four partitions in the MBR by reading the table
127 * information into our mbr table.
128 */
129 partition_count = 0;
130 idx = TABLE_ENTRY_0;
131 for (i = 0; i < 4; i++) {
132 /* Type 0xEE indicates end of MBR and GPT partitions exist */
133 dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
134 if (dtype == MBR_PROTECTED_TYPE) {
135 gpt_partitions_exist = 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700136 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800137 }
138 partition_entries[partition_count].dtype = dtype;
139 partition_entries[partition_count].attribute_flag =
140 buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
141 partition_entries[partition_count].first_lba =
142 GET_LWORD_FROM_BYTE(&buffer[idx +
143 i * TABLE_ENTRY_SIZE +
144 OFFSET_FIRST_SEC]);
145 partition_entries[partition_count].size =
146 GET_LWORD_FROM_BYTE(&buffer[idx +
147 i * TABLE_ENTRY_SIZE +
148 OFFSET_SIZE]);
149 dfirstsec = partition_entries[partition_count].first_lba;
150 mbr_fill_name(&partition_entries[partition_count],
151 partition_entries[partition_count].dtype);
152 partition_count++;
153 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700154 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800155 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700156
Ajay Dudanib01e5062011-12-03 23:23:42 -0800157 /* See if the last partition is EBR, if not, parsing is done */
158 if (dtype != MBR_EBR_TYPE) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700159 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800160 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700161
Ajay Dudanib01e5062011-12-03 23:23:42 -0800162 EBR_first_sec = dfirstsec;
163 EBR_current_sec = dfirstsec;
Kinson Chikf1a43512011-07-14 11:28:39 -0700164
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700165 ret = mmc_read((EBR_first_sec * block_size), (unsigned int *)buffer, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700166 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700167 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700168
Ajay Dudanib01e5062011-12-03 23:23:42 -0800169 /* Loop to parse the EBR */
170 for (i = 0;; i++) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700171 ret = partition_verify_mbr_signature(block_size, buffer);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800172 if (ret) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700173 ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800174 break;
175 }
176 partition_entries[partition_count].attribute_flag =
177 buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
178 partition_entries[partition_count].dtype =
179 buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
180 partition_entries[partition_count].first_lba =
181 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
182 OFFSET_FIRST_SEC]) +
183 EBR_current_sec;
184 partition_entries[partition_count].size =
185 GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
186 mbr_fill_name(&(partition_entries[partition_count]),
187 partition_entries[partition_count].dtype);
188 partition_count++;
189 if (partition_count == NUM_PARTITIONS)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700190 goto end;
Kinson Chikf1a43512011-07-14 11:28:39 -0700191
Ajay Dudanib01e5062011-12-03 23:23:42 -0800192 dfirstsec =
193 GET_LWORD_FROM_BYTE(&buffer
194 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
195 if (dfirstsec == 0) {
196 /* Getting to the end of the EBR tables */
197 break;
198 }
199 /* More EBR to follow - read in the next EBR sector */
200 dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
201 + dfirstsec);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700202 ret = mmc_read(((EBR_first_sec + dfirstsec) * block_size),(unsigned int *)buffer,
203 block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700204 if (ret)
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700205 goto end;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700206
Ajay Dudanib01e5062011-12-03 23:23:42 -0800207 EBR_current_sec = EBR_first_sec + dfirstsec;
208 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700209end:
210 if (buffer)
211 free(buffer);
212
Ajay Dudanib01e5062011-12-03 23:23:42 -0800213 return ret;
Kinson Chikf1a43512011-07-14 11:28:39 -0700214}
Kinson Chik66552a82011-03-29 15:59:06 -0700215
216/*
217 * Read GPT from MMC and fill partition table
218 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700219static unsigned int mmc_boot_read_gpt(uint32_t block_size)
Kinson Chikf1a43512011-07-14 11:28:39 -0700220{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700221 int ret = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800222 unsigned int header_size;
223 unsigned long long first_usable_lba;
224 unsigned long long backup_header_lba;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700225 unsigned long long card_size_sec;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800226 unsigned int max_partition_count = 0;
227 unsigned int partition_entry_size;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700228 unsigned int i = 0; /* Counter for each block */
229 unsigned int j = 0; /* Counter for each entry in a block */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800230 unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
231 unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
232 /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700233 unsigned long long partition_0;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700234 uint64_t device_density;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700235 uint8_t *data = NULL;
236 uint32_t part_entry_cnt = block_size / ENTRY_SIZE;
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700237
Ajay Dudanib01e5062011-12-03 23:23:42 -0800238 partition_count = 0;
Kinson Chik66552a82011-03-29 15:59:06 -0700239
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700240 /* Get the density of the mmc device */
241
242 device_density = mmc_get_device_capacity();
243
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700244 data = (uint8_t *)memalign(CACHE_LINE, ROUNDUP(block_size, CACHE_LINE));
245 if (!data)
246 {
247 dprintf(CRITICAL, "Failed to Allocate memory to read partition table\n");
248 ret = -1;
249 goto end;
250 }
251
Ajay Dudanib01e5062011-12-03 23:23:42 -0800252 /* Print out the GPT first */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700253 ret = mmc_read(block_size, (unsigned int *)data, block_size);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700254 if (ret)
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700255 {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800256 dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700257 goto end;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700258 }
Kinson Chik66552a82011-03-29 15:59:06 -0700259
Ajay Dudanib01e5062011-12-03 23:23:42 -0800260 ret = partition_parse_gpt_header(data, &first_usable_lba,
261 &partition_entry_size, &header_size,
262 &max_partition_count);
263 if (ret) {
264 dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
Kinson Chik4d7444f2011-09-13 15:48:51 -0700265
Ajay Dudanib01e5062011-12-03 23:23:42 -0800266 /* Check the backup gpt */
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700267
268 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700269 card_size_sec = (device_density) / block_size;
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700270 ASSERT (card_size_sec > 0);
271
272 backup_header_lba = card_size_sec - 1;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700273 ret = mmc_read((backup_header_lba * block_size), (unsigned int *)data,
274 block_size);
Kinson Chik4d7444f2011-09-13 15:48:51 -0700275
Ajay Dudanib01e5062011-12-03 23:23:42 -0800276 if (ret) {
277 dprintf(CRITICAL,
278 "GPT: Could not read backup gpt from mmc\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700279 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800280 }
Kinson Chik4d7444f2011-09-13 15:48:51 -0700281
Ajay Dudanib01e5062011-12-03 23:23:42 -0800282 ret = partition_parse_gpt_header(data, &first_usable_lba,
283 &partition_entry_size,
284 &header_size,
285 &max_partition_count);
286 if (ret) {
287 dprintf(CRITICAL,
288 "GPT: Primary and backup signatures invalid\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700289 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800290 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800291 }
Neeti Desaice6ad9a2012-03-21 18:57:59 -0700292 partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800293 /* Read GPT Entries */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700294 for (i = 0; i < (ROUNDUP(max_partition_count, part_entry_cnt)) / part_entry_cnt; i++) {
neetid6c38de12011-12-02 12:04:50 -0800295 ASSERT(partition_count < NUM_PARTITIONS);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700296 ret = mmc_read((partition_0 * block_size) + (i * block_size),
297 (uint32_t *) data, block_size);
Kinson Chik66552a82011-03-29 15:59:06 -0700298
Ajay Dudanib01e5062011-12-03 23:23:42 -0800299 if (ret) {
300 dprintf(CRITICAL,
301 "GPT: mmc read card failed reading partition entries.\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700302 goto end;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800303 }
Kinson Chik66552a82011-03-29 15:59:06 -0700304
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700305 for (j = 0; j < part_entry_cnt; j++) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800306 memcpy(&(partition_entries[partition_count].type_guid),
307 &data[(j * partition_entry_size)],
308 PARTITION_TYPE_GUID_SIZE);
309 if (partition_entries[partition_count].type_guid[0] ==
310 0x00
311 && partition_entries[partition_count].
312 type_guid[1] == 0x00) {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700313 i = ROUNDUP(max_partition_count, part_entry_cnt);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800314 break;
315 }
316 memcpy(&
317 (partition_entries[partition_count].
318 unique_partition_guid),
319 &data[(j * partition_entry_size) +
320 UNIQUE_GUID_OFFSET],
321 UNIQUE_PARTITION_GUID_SIZE);
322 partition_entries[partition_count].first_lba =
323 GET_LLWORD_FROM_BYTE(&data
324 [(j * partition_entry_size) +
325 FIRST_LBA_OFFSET]);
326 partition_entries[partition_count].last_lba =
327 GET_LLWORD_FROM_BYTE(&data
328 [(j * partition_entry_size) +
329 LAST_LBA_OFFSET]);
330 partition_entries[partition_count].size =
331 partition_entries[partition_count].last_lba -
Neeti Desai4b8c1df2012-03-21 13:15:14 -0700332 partition_entries[partition_count].first_lba + 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800333 partition_entries[partition_count].attribute_flag =
334 GET_LLWORD_FROM_BYTE(&data
335 [(j * partition_entry_size) +
336 ATTRIBUTE_FLAG_OFFSET]);
Kinson Chik66552a82011-03-29 15:59:06 -0700337
Ajay Dudanib01e5062011-12-03 23:23:42 -0800338 memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
339 memcpy(UTF16_name, &data[(j * partition_entry_size) +
340 PARTITION_NAME_OFFSET],
341 MAX_GPT_NAME_SIZE);
342 /*
343 * Currently partition names in *.xml are UTF-8 and lowercase
344 * Only supporting english for now so removing 2nd byte of UTF-16
345 */
346 for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
347 partition_entries[partition_count].name[n] =
348 UTF16_name[n * 2];
349 }
350 partition_count++;
351 }
352 }
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700353end:
354 if (data)
355 free(data);
356
Ajay Dudanib01e5062011-12-03 23:23:42 -0800357 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700358}
359
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700360static unsigned int write_mbr_in_blocks(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700361{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800362 unsigned int dtype;
363 unsigned int dfirstsec;
364 unsigned int ebrSectorOffset;
365 unsigned char *ebrImage;
366 unsigned char *lastAddress;
367 int idx, i;
368 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700369
Ajay Dudanib01e5062011-12-03 23:23:42 -0800370 /* Write the first block */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700371 ret = mmc_write(0, block_size, (unsigned int *)mbrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800372 if (ret) {
373 dprintf(CRITICAL, "Failed to write mbr partition\n");
374 goto end;
375 }
376 dprintf(SPEW, "write of first MBR block ok\n");
377 /*
378 Loop through the MBR table to see if there is an EBR.
379 If found, then figure out where to write the first EBR
380 */
381 idx = TABLE_ENTRY_0;
382 for (i = 0; i < 4; i++) {
383 dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
384 if (MBR_EBR_TYPE == dtype) {
385 dprintf(SPEW, "EBR found.\n");
386 break;
387 }
388 }
389 if (MBR_EBR_TYPE != dtype) {
390 dprintf(SPEW, "No EBR in this image\n");
391 goto end;
392 }
393 /* EBR exists. Write each EBR block to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700394 ebrImage = mbrImage + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800395 ebrSectorOffset =
396 GET_LWORD_FROM_BYTE(&mbrImage
397 [idx + i * TABLE_ENTRY_SIZE +
398 OFFSET_FIRST_SEC]);
399 dfirstsec = 0;
400 dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
401 lastAddress = mbrImage + size;
402 while (ebrImage < lastAddress) {
403 dprintf(SPEW, "writing to 0x%X\n",
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700404 (ebrSectorOffset + dfirstsec) * block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800405 ret =
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700406 mmc_write((ebrSectorOffset + dfirstsec) * block_size,
407 block_size, (unsigned int *)ebrImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800408 if (ret) {
409 dprintf(CRITICAL,
410 "Failed to write EBR block to sector 0x%X\n",
411 dfirstsec);
412 goto end;
413 }
414 dfirstsec =
415 GET_LWORD_FROM_BYTE(&ebrImage
416 [TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700417 ebrImage += block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800418 }
419 dprintf(INFO, "MBR written to mmc successfully\n");
420 end:
421 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700422}
423
424/* Write the MBR/EBR to the MMC. */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700425static unsigned int write_mbr(uint32_t size, uint8_t *mbrImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700426{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800427 unsigned int ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700428
Ajay Dudanib01e5062011-12-03 23:23:42 -0800429 /* Verify that passed in block is a valid MBR */
430 ret = partition_verify_mbr_signature(size, mbrImage);
431 if (ret) {
432 goto end;
433 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700434
Ajay Dudanib01e5062011-12-03 23:23:42 -0800435 /* Write the MBR/EBR to mmc */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700436 ret = write_mbr_in_blocks(size, mbrImage, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800437 if (ret) {
438 dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
439 goto end;
440 }
441 /* Re-read the MBR partition into mbr table */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700442 ret = mmc_boot_read_mbr(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800443 if (ret) {
444 dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
445 goto end;
446 }
447 partition_dump();
448 end:
449 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700450}
451
452/*
453 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
454*/
455int reflect(int data, int len)
456{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800457 int ref = 0;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700458
Ajay Dudanib01e5062011-12-03 23:23:42 -0800459 for (int i = 0; i < len; i++) {
460 if (data & 0x1) {
461 ref |= (1 << ((len - 1) - i));
462 }
463 data = (data >> 1);
464 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700465
Ajay Dudanib01e5062011-12-03 23:23:42 -0800466 return ref;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700467}
468
469/*
470* Function to calculate the CRC32
471*/
472unsigned int calculate_crc32(unsigned char *buffer, int len)
473{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800474 int byte_length = 8; /*length of unit (i.e. byte) */
475 int msb = 0;
Channagoud Kadabi39f13522013-07-31 14:46:22 -0700476 int polynomial = 0x04C11DB7; /* IEEE 32bit polynomial */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800477 unsigned int regs = 0xFFFFFFFF; /* init to all ones */
478 int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
479 int regs_msb = 0;
480 unsigned int reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700481
Ajay Dudanib01e5062011-12-03 23:23:42 -0800482 for (int i = 0; i < len; i++) {
483 int data_byte = buffer[i];
484 data_byte = reflect(data_byte, 8);
485 for (int j = 0; j < byte_length; j++) {
486 msb = data_byte >> (byte_length - 1); /* get MSB */
487 msb &= 1; /* ensure just 1 bit */
488 regs_msb = (regs >> 31) & 1; /* MSB of regs */
489 regs = regs << 1; /* shift regs for CRC-CCITT */
490 if (regs_msb ^ msb) { /* MSB is a 1 */
491 regs = regs ^ polynomial; /* XOR with generator poly */
492 }
493 regs = regs & regs_mask; /* Mask off excess upper bits */
494 data_byte <<= 1; /* get to next bit */
495 }
496 }
497 regs = regs & regs_mask;
498 reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700499
Ajay Dudanib01e5062011-12-03 23:23:42 -0800500 return reflected_regs;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700501}
502
503/*
504 * Write the GPT Partition Entry Array to the MMC.
505 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800506static unsigned int
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700507write_gpt_partition_array(uint8_t *header,
508 uint32_t partition_array_start,
509 uint32_t array_size,
510 uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700511{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700512 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800513 unsigned long long partition_entry_lba;
514 unsigned long long partition_entry_array_start_location;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700515
Ajay Dudanib01e5062011-12-03 23:23:42 -0800516 partition_entry_lba =
517 GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700518 partition_entry_array_start_location = partition_entry_lba * block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700519
Ajay Dudanib01e5062011-12-03 23:23:42 -0800520 ret = mmc_write(partition_entry_array_start_location, array_size,
521 (unsigned int *)partition_array_start);
522 if (ret) {
523 dprintf(CRITICAL,
524 "GPT: FAILED to write the partition entry array\n");
525 goto end;
526 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700527
Ajay Dudanib01e5062011-12-03 23:23:42 -0800528 end:
529 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700530}
531
Ajay Dudanib01e5062011-12-03 23:23:42 -0800532static void
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700533patch_gpt(uint8_t *gptImage, uint64_t density, uint32_t array_size,
534 uint32_t max_part_count, uint32_t part_entry_size, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700535{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800536 unsigned int partition_entry_array_start;
537 unsigned char *primary_gpt_header;
538 unsigned char *secondary_gpt_header;
539 unsigned int offset;
540 unsigned long long card_size_sec;
541 int total_part = 0;
542 unsigned int last_part_offset;
543 unsigned int crc_value;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700544
Ajay Dudanib01e5062011-12-03 23:23:42 -0800545 /* Get size of MMC */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700546 card_size_sec = (density) / block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800547 /* Working around cap at 4GB */
548 if (card_size_sec == 0) {
549 card_size_sec = 4 * 1024 * 1024 * 2 - 1;
550 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700551
Ajay Dudanib01e5062011-12-03 23:23:42 -0800552 /* Patching primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700553 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800554 PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
555 ((long long)(card_size_sec - 1)));
556 PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
557 ((long long)(card_size_sec - 34)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700558
Ajay Dudanib01e5062011-12-03 23:23:42 -0800559 /* Patching backup GPT */
560 offset = (2 * array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700561 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800562 PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
563 ((long long)(card_size_sec - 1)));
564 PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
565 ((long long)(card_size_sec - 34)));
566 PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
567 ((long long)(card_size_sec - 33)));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700568
Ajay Dudanib01e5062011-12-03 23:23:42 -0800569 /* Find last partition */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700570 while (*(primary_gpt_header + block_size + total_part * ENTRY_SIZE) !=
Ajay Dudanib01e5062011-12-03 23:23:42 -0800571 0) {
572 total_part++;
573 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700574
Ajay Dudanib01e5062011-12-03 23:23:42 -0800575 /* Patching last partition */
576 last_part_offset =
577 (total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700578 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800579 (long long)(card_size_sec - 34));
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700580 PUT_LONG_LONG(primary_gpt_header + block_size + last_part_offset +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800581 array_size, (long long)(card_size_sec - 34));
Neeti Desai5f26aff2011-09-30 10:27:40 -0700582
Ajay Dudanib01e5062011-12-03 23:23:42 -0800583 /* Updating CRC of the Partition entry array in both headers */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700584 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800585 crc_value = calculate_crc32(partition_entry_array_start,
586 max_part_count * part_entry_size);
587 PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700588
Ajay Dudanib01e5062011-12-03 23:23:42 -0800589 crc_value = calculate_crc32(partition_entry_array_start + array_size,
590 max_part_count * part_entry_size);
591 PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700592
Ajay Dudanib01e5062011-12-03 23:23:42 -0800593 /* Clearing CRC fields to calculate */
594 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
595 crc_value = calculate_crc32(primary_gpt_header, 92);
596 PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700597
Ajay Dudanib01e5062011-12-03 23:23:42 -0800598 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
599 crc_value = (calculate_crc32(secondary_gpt_header, 92));
600 PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700601
602}
603
604/*
605 * Write the GPT to the MMC.
606 */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700607static unsigned int write_gpt(uint32_t size, uint8_t *gptImage, uint32_t block_size)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700608{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700609 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800610 unsigned int header_size;
611 unsigned long long first_usable_lba;
612 unsigned long long backup_header_lba;
613 unsigned int max_partition_count = 0;
614 unsigned int partition_entry_size;
615 unsigned int partition_entry_array_start;
616 unsigned char *primary_gpt_header;
617 unsigned char *secondary_gpt_header;
618 unsigned int offset;
619 unsigned int partition_entry_array_size;
620 unsigned long long primary_header_location; /* address on the emmc card */
621 unsigned long long secondary_header_location; /* address on the emmc card */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700622 uint64_t device_density;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700623
Ajay Dudanib01e5062011-12-03 23:23:42 -0800624 /* Verify that passed block has a valid GPT primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700625 primary_gpt_header = (gptImage + block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800626 ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
627 &partition_entry_size, &header_size,
628 &max_partition_count);
629 if (ret) {
630 dprintf(CRITICAL,
631 "GPT: Primary signature invalid cannot write GPT\n");
632 goto end;
633 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700634
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700635 /* Get the density of the mmc device */
636
637 device_density = mmc_get_device_capacity();
638
Ajay Dudanib01e5062011-12-03 23:23:42 -0800639 /* Verify that passed block has a valid backup GPT HEADER */
640 partition_entry_array_size = partition_entry_size * max_partition_count;
641 if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
642 partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
643 }
644 offset = (2 * partition_entry_array_size);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700645 secondary_gpt_header = offset + block_size + primary_gpt_header;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800646 ret =
647 partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
648 &partition_entry_size, &header_size,
649 &max_partition_count);
650 if (ret) {
651 dprintf(CRITICAL,
652 "GPT: Backup signature invalid cannot write GPT\n");
653 goto end;
654 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700655
Ajay Dudanib01e5062011-12-03 23:23:42 -0800656 /* Patching the primary and the backup header of the GPT table */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700657 patch_gpt(gptImage, device_density, partition_entry_array_size,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700658 max_partition_count, partition_entry_size, block_size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700659
Ajay Dudanib01e5062011-12-03 23:23:42 -0800660 /* Erasing the eMMC card before writing */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700661 ret = mmc_erase_card(0x00000000, device_density);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800662 if (ret) {
663 dprintf(CRITICAL, "Failed to erase the eMMC card\n");
664 goto end;
665 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700666
Ajay Dudanib01e5062011-12-03 23:23:42 -0800667 /* Writing protective MBR */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700668 ret = mmc_write(0, block_size, (unsigned int *)gptImage);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800669 if (ret) {
670 dprintf(CRITICAL, "Failed to write Protective MBR\n");
671 goto end;
672 }
673 /* Writing the primary GPT header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700674 primary_header_location = block_size;
675 ret = mmc_write(primary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800676 (unsigned int *)primary_gpt_header);
677 if (ret) {
678 dprintf(CRITICAL, "Failed to write GPT header\n");
679 goto end;
680 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700681
Ajay Dudanib01e5062011-12-03 23:23:42 -0800682 /* Writing the backup GPT header */
683 backup_header_lba = GET_LLWORD_FROM_BYTE
684 (&primary_gpt_header[BACKUP_HEADER_OFFSET]);
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700685 secondary_header_location = backup_header_lba * block_size;
686 ret = mmc_write(secondary_header_location, block_size,
Ajay Dudanib01e5062011-12-03 23:23:42 -0800687 (unsigned int *)secondary_gpt_header);
688 if (ret) {
689 dprintf(CRITICAL, "Failed to write GPT backup header\n");
690 goto end;
691 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700692
Ajay Dudanib01e5062011-12-03 23:23:42 -0800693 /* Writing the partition entries array for the primary header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700694 partition_entry_array_start = primary_gpt_header + block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800695 ret = write_gpt_partition_array(primary_gpt_header,
696 partition_entry_array_start,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700697 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800698 if (ret) {
699 dprintf(CRITICAL,
700 "GPT: Could not write GPT Partition entries array\n");
701 goto end;
702 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700703
Ajay Dudanib01e5062011-12-03 23:23:42 -0800704 /*Writing the partition entries array for the backup header */
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700705 partition_entry_array_start = primary_gpt_header + block_size +
Ajay Dudanib01e5062011-12-03 23:23:42 -0800706 partition_entry_array_size;
707 ret = write_gpt_partition_array(secondary_gpt_header,
708 partition_entry_array_start,
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700709 partition_entry_array_size, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800710 if (ret) {
711 dprintf(CRITICAL,
712 "GPT: Could not write GPT Partition entries array\n");
713 goto end;
714 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700715
Ajay Dudanib01e5062011-12-03 23:23:42 -0800716 /* Re-read the GPT partition table */
717 dprintf(INFO, "Re-reading the GPT Partition Table\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700718 ret = mmc_boot_read_gpt(block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800719 if (ret) {
720 dprintf(CRITICAL,
721 "GPT: Failure to re- read the GPT Partition table\n");
722 goto end;
723 }
724 partition_dump();
725 dprintf(CRITICAL, "GPT: Partition Table written\n");
726 memset(primary_gpt_header, 0x00, size);
Neeti Desai5f26aff2011-09-30 10:27:40 -0700727
Ajay Dudanib01e5062011-12-03 23:23:42 -0800728 end:
729 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700730}
731
Ajay Dudanib01e5062011-12-03 23:23:42 -0800732unsigned int write_partition(unsigned size, unsigned char *partition)
Neeti Desai5f26aff2011-09-30 10:27:40 -0700733{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700734 unsigned int ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800735 unsigned int partition_type;
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700736 uint32_t block_size;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700737
Ajay Dudanib01e5062011-12-03 23:23:42 -0800738 if (partition == 0) {
739 dprintf(CRITICAL, "NULL partition\n");
740 goto end;
741 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700742
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700743 block_size = mmc_get_device_blocksize();
Ajay Dudanib01e5062011-12-03 23:23:42 -0800744 ret = partition_get_type(size, partition, &partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700745 if (ret)
Ajay Dudanib01e5062011-12-03 23:23:42 -0800746 goto end;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700747
Ajay Dudanib01e5062011-12-03 23:23:42 -0800748 switch (partition_type) {
749 case PARTITION_TYPE_MBR:
750 dprintf(INFO, "Writing MBR partition\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700751 ret = write_mbr(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800752 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700753
Ajay Dudanib01e5062011-12-03 23:23:42 -0800754 case PARTITION_TYPE_GPT:
755 dprintf(INFO, "Writing GPT partition\n");
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700756 ret = write_gpt(size, partition, block_size);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800757 dprintf(CRITICAL, "Re-Flash all the partitions\n");
758 break;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700759
Ajay Dudanib01e5062011-12-03 23:23:42 -0800760 default:
761 dprintf(CRITICAL, "Invalid partition\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700762 ret = 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800763 goto end;
764 }
Neeti Desai5f26aff2011-09-30 10:27:40 -0700765
Ajay Dudanib01e5062011-12-03 23:23:42 -0800766 end:
767 return ret;
Neeti Desai5f26aff2011-09-30 10:27:40 -0700768}
Ajay Dudanib01e5062011-12-03 23:23:42 -0800769
Kinson Chikf1a43512011-07-14 11:28:39 -0700770/*
771 * Fill name for android partition found.
772 */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800773static void
774mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700775{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800776 switch (type) {
777 memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
778 case MBR_MODEM_TYPE:
779 case MBR_MODEM_TYPE2:
780 /* if already assigned last name available then return */
781 if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
782 return;
783 strlcpy((char *)partition_ent->name,
784 (const char *)vfat_partitions[vfat_count],
785 sizeof(partition_ent->name));
786 vfat_count++;
787 break;
788 case MBR_SBL1_TYPE:
789 memcpy(partition_ent->name, "sbl1", 4);
790 break;
791 case MBR_SBL2_TYPE:
792 memcpy(partition_ent->name, "sbl2", 4);
793 break;
794 case MBR_SBL3_TYPE:
795 memcpy(partition_ent->name, "sbl3", 4);
796 break;
797 case MBR_RPM_TYPE:
798 memcpy(partition_ent->name, "rpm", 3);
799 break;
800 case MBR_TZ_TYPE:
801 memcpy(partition_ent->name, "tz", 2);
802 break;
803 case MBR_ABOOT_TYPE:
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530804#if PLATFORM_MSM7X27A
805 memcpy(partition_ent->name, "FOTA", 4);
806#else
Ajay Dudanib01e5062011-12-03 23:23:42 -0800807 memcpy(partition_ent->name, "aboot", 5);
Channagoud Kadabi16f50952012-04-02 16:24:07 +0530808#endif
Ajay Dudanib01e5062011-12-03 23:23:42 -0800809 break;
810 case MBR_BOOT_TYPE:
811 memcpy(partition_ent->name, "boot", 4);
812 break;
813 case MBR_MODEM_ST1_TYPE:
814 memcpy(partition_ent->name, "modem_st1", 9);
815 break;
816 case MBR_MODEM_ST2_TYPE:
817 memcpy(partition_ent->name, "modem_st2", 9);
818 break;
819 case MBR_EFS2_TYPE:
820 memcpy(partition_ent->name, "efs2", 4);
821 break;
822 case MBR_USERDATA_TYPE:
823 if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
824 return;
825 strlcpy((char *)partition_ent->name,
826 (const char *)ext3_partitions[ext3_count],
827 sizeof(partition_ent->name));
828 ext3_count++;
829 break;
830 case MBR_RECOVERY_TYPE:
831 memcpy(partition_ent->name, "recovery", 8);
832 break;
833 case MBR_MISC_TYPE:
834 memcpy(partition_ent->name, "misc", 4);
835 break;
Neeti Desai2d6b0e42012-03-23 15:48:57 -0700836 case MBR_SSD_TYPE:
837 memcpy(partition_ent->name, "ssd", 3);
838 break;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800839 };
Kinson Chikf1a43512011-07-14 11:28:39 -0700840}
841
842/*
843 * Find index of parition in array of partition entries
844 */
Pavel Nedev285ad922013-04-26 10:39:19 +0300845int partition_get_index(const char *name)
Kinson Chikf1a43512011-07-14 11:28:39 -0700846{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800847 unsigned int input_string_length = strlen(name);
848 unsigned n;
Kinson Chik66552a82011-03-29 15:59:06 -0700849
neetid6c38de12011-12-02 12:04:50 -0800850 if( partition_count >= NUM_PARTITIONS)
851 {
852 return INVALID_PTN;
853 }
Ajay Dudanib01e5062011-12-03 23:23:42 -0800854 for (n = 0; n < partition_count; n++) {
855 if (!memcmp
856 (name, &partition_entries[n].name, input_string_length)
857 && input_string_length ==
858 strlen((const char *)&partition_entries[n].name)) {
859 return n;
860 }
861 }
862 return INVALID_PTN;
Kinson Chikf1a43512011-07-14 11:28:39 -0700863}
864
865/* Get size of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800866unsigned long long partition_get_size(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700867{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700868 uint32_t block_size;
869
870 block_size = mmc_get_device_blocksize();
871
Ajay Dudanib01e5062011-12-03 23:23:42 -0800872 if (index == INVALID_PTN)
873 return 0;
874 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700875 return partition_entries[index].size * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800876 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700877}
878
879/* Get offset of the partition */
Ajay Dudanib01e5062011-12-03 23:23:42 -0800880unsigned long long partition_get_offset(int index)
Kinson Chikf1a43512011-07-14 11:28:39 -0700881{
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700882 uint32_t block_size;
883
884 block_size = mmc_get_device_blocksize();
885
Ajay Dudanib01e5062011-12-03 23:23:42 -0800886 if (index == INVALID_PTN)
887 return 0;
888 else {
Channagoud Kadabi57eb6302013-09-10 14:21:30 -0700889 return partition_entries[index].first_lba * block_size;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800890 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700891}
892
893/* Debug: Print all parsed partitions */
894void partition_dump()
895{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800896 unsigned i = 0;
897 for (i = 0; i < partition_count; i++) {
898 dprintf(SPEW,
899 "ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
900 i, partition_entries[i].name, partition_entries[i].size,
901 partition_entries[i].dtype,
902 partition_entries[i].first_lba,
903 partition_entries[i].last_lba);
904 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700905}
906
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700907static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800908partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
Kinson Chikf1a43512011-07-14 11:28:39 -0700909{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800910 /* Avoid checking past end of buffer */
911 if ((TABLE_SIGNATURE + 1) > size) {
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700912 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800913 }
914 /* Check to see if signature exists */
915 if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
916 (buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
917 dprintf(CRITICAL, "MBR signature does not match.\n");
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700918 return 1;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800919 }
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700920 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700921}
922
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700923static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800924mbr_partition_get_type(unsigned size, unsigned char *partition,
925 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700926{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800927 unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
Kinson Chikf1a43512011-07-14 11:28:39 -0700928
Ajay Dudanib01e5062011-12-03 23:23:42 -0800929 if (size < type_offset) {
930 goto end;
931 }
Kinson Chikf1a43512011-07-14 11:28:39 -0700932
Ajay Dudanib01e5062011-12-03 23:23:42 -0800933 *partition_type = partition[type_offset];
934 end:
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700935 return 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700936}
937
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700938static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800939partition_get_type(unsigned size, unsigned char *partition,
940 unsigned int *partition_type)
Kinson Chikf1a43512011-07-14 11:28:39 -0700941{
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700942 unsigned int ret = 0;
Kinson Chikf1a43512011-07-14 11:28:39 -0700943
Ajay Dudanib01e5062011-12-03 23:23:42 -0800944 /*
945 * If the block contains the MBR signature, then it's likely either
946 * MBR or MBR with protective type (GPT). If the MBR signature is
947 * not there, then it could be the GPT backup.
948 */
Kinson Chikf1a43512011-07-14 11:28:39 -0700949
Ajay Dudanib01e5062011-12-03 23:23:42 -0800950 /* First check the MBR signature */
951 ret = partition_verify_mbr_signature(size, partition);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700952 if (!ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800953 unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
Kinson Chikf1a43512011-07-14 11:28:39 -0700954
Ajay Dudanib01e5062011-12-03 23:23:42 -0800955 /* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
956 ret =
957 mbr_partition_get_type(size, partition,
958 &mbr_partition_type);
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700959 if (ret) {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800960 dprintf(CRITICAL, "Cannot get TYPE of partition");
961 } else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
962 *partition_type = PARTITION_TYPE_GPT;
963 } else {
964 *partition_type = PARTITION_TYPE_MBR;
965 }
966 } else {
967 /*
968 * This could be the GPT backup. Make that assumption for now.
969 * Anybody who treats the block as GPT backup should check the
970 * signature.
971 */
972 *partition_type = PARTITION_TYPE_GPT_BACKUP;
973 }
974 return ret;
Kinson Chik66552a82011-03-29 15:59:06 -0700975}
Kinson Chik4d7444f2011-09-13 15:48:51 -0700976
977/*
978 * Parse the gpt header and get the required header fields
979 * Return 0 on valid signature
980 */
Channagoud Kadabi0e332852013-04-19 12:55:53 -0700981static unsigned int
Ajay Dudanib01e5062011-12-03 23:23:42 -0800982partition_parse_gpt_header(unsigned char *buffer,
983 unsigned long long *first_usable_lba,
984 unsigned int *partition_entry_size,
985 unsigned int *header_size,
986 unsigned int *max_partition_count)
Kinson Chik4d7444f2011-09-13 15:48:51 -0700987{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800988 /* Check GPT Signature */
989 if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
990 ((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
991 return 1;
Kinson Chik4d7444f2011-09-13 15:48:51 -0700992
Ajay Dudanib01e5062011-12-03 23:23:42 -0800993 *header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
994 *first_usable_lba =
995 GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
996 *max_partition_count =
997 GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
998 *partition_entry_size =
999 GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
Kinson Chik4d7444f2011-09-13 15:48:51 -07001000
Ajay Dudanib01e5062011-12-03 23:23:42 -08001001 return 0;
Kinson Chik4d7444f2011-09-13 15:48:51 -07001002}
Pavel Nedevb5ba62d2013-07-22 11:57:41 +03001003
1004bool partition_gpt_exists()
1005{
1006 return (gpt_partitions_exist != 0);
1007}