blob: 9e64ec147d24cd60d9c8f87e854c36cc18792e24 [file] [log] [blame]
Mayank Grovered699202017-05-30 20:04:10 +05301/*
2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 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 copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of The Linux Foundation nor
12 * the names of its contributors may be used to endorse or promote
13 * products derived from this software without specific prior written
14 * permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29#include <stdlib.h>
30#include <string.h>
31#include <crc32.h>
32#include <ab_partition_parser.h>
33#include <partition_parser.h>
Mayank Grover9c866202017-06-29 17:48:55 +053034#include <boot_device.h>
35#if defined(MMC_SDHCI_SUPPORT) || defined(UFS_SUPPORT)
36#include <mmc_wrapper.h>
37#include <ufs.h>
38#endif
Mayank Grovered699202017-05-30 20:04:10 +053039
40//#define AB_DEBUG
41
42/* Slot suffix */
43const char *suffix_slot[] = {"_a",
44 "_b"};
Mayank Grover6ccc1c92017-07-04 17:36:46 +053045const char *suffix_delimiter = "_";
Mayank Grovered699202017-05-30 20:04:10 +053046
47/* local global variables */
Mayank Grover25e3e3a2017-08-24 15:11:58 +053048static signed active_slot; /* to store current active slot */
49static bool attributes_updated; /* to store if we need to update partition table */
50static bool multislot_support; /* to store if multislot support is present */
Mayank Grovered699202017-05-30 20:04:10 +053051
52static int boot_slot_index[AB_SUPPORTED_SLOTS]; /* store index for boot parition */
53
54/* local functions. */
55static void attributes_update();
56
57/*
58 Function: To read slot attribute of
59 of the partition_entry
60*/
61inline bool slot_is_active(struct partition_entry *partition_entries,
62 unsigned index)
63{
64 if ((partition_entries[index].attribute_flag &
65 PART_ATT_ACTIVE_VAL)>>PART_ATT_ACTIVE_BIT)
66 return true;
67 else
68 return false;
69}
70
71inline bool slot_is_sucessful(struct partition_entry *partition_entries,
72 unsigned index)
73{
74 if ((partition_entries[index].attribute_flag &
75 PART_ATT_SUCCESSFUL_VAL)>>PART_ATT_SUCCESS_BIT)
76 return true;
77 else
78 return false;
79}
80
81inline unsigned slot_retry_count(struct partition_entry *partition_entries,
82 unsigned index)
83{
84 return ((partition_entries[index].attribute_flag
85 & PART_ATT_MAX_RETRY_COUNT_VAL) >> PART_ATT_MAX_RETRY_CNT_BIT);
86}
87
88inline unsigned slot_priority(struct partition_entry *partition_entries,
89 unsigned index)
90{
91 return ((partition_entries[index].attribute_flag
92 & PART_ATT_PRIORITY_VAL)>>PART_ATT_PRIORITY_BIT);
93}
94
95inline bool slot_is_bootable(struct partition_entry *partition_entries,
96 unsigned index)
97{
98 if ((partition_entries[index].attribute_flag &
99 PART_ATT_UNBOOTABLE_VAL)>>PART_ATT_UNBOOTABLE_BIT)
100 return false;
101 else
102 return true;
103}
104
105/*
106 Function scan boot partition to find SLOT_A/SLOT_B suffix.
107 If found than make multislot_boot flag true and
108 scans another partition.
109*/
110bool partition_scan_for_multislot()
111{
112 int i, j, count = 0;
113 char *pname = NULL;
114 int strlen_boot = strlen("boot");
115 int partition_count = partition_get_partition_count();
116 struct partition_entry *partition_entries =
117 partition_get_partition_entries();
118
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530119 /* Intialize all slot specific variables */
Mayank Grovered699202017-05-30 20:04:10 +0530120 multislot_support = false;
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530121 active_slot = INVALID;
122 attributes_updated = false;
Mayank Grovered699202017-05-30 20:04:10 +0530123
124 if (partition_count > NUM_PARTITIONS)
125 {
126 dprintf(CRITICAL, "ERROR: partition_count more than supported.\n");
127 return multislot_support;
128 }
129
130 for (i = 0; i < partition_count; i++)
131 {
132 pname = (char *)partition_entries[i].name;
133#ifdef AB_DEBUG
134 dprintf(INFO, "Transversing partition %s\n", pname);
135#endif
136 if (!strncmp((const char *)partition_entries[i].name, "boot", strlen_boot))
137 {
138 pname += strlen_boot;
139 if (*pname)
140 {
141#ifdef AB_DEBUG
142 dprintf(INFO, "Suffix: %s\n", pname);
143#endif
144 for (j =0; j<AB_SUPPORTED_SLOTS; j++)
145 {
146 if (!strcmp(pname, suffix_slot[j]))
147 {
148 /* cache these variables as they are used multiple times */
149 boot_slot_index[j] = i;
150 if (!multislot_support)
151 multislot_support =true;
152 count ++;
153 }
154 }
155 /* Break out of loop if all slot index are found*/
156 if (count == AB_SUPPORTED_SLOTS)
157 break;
158 }
159 else
160 {
161#ifdef AB_DEBUG
162 dprintf(INFO, "Partition Table is not a/b supported\n");
163#endif
164 break;
165 }
166 }
167 }
168 return multislot_support;
169}
170
171/*
172 Function: To reset partition attributes
173 This function reset partition_priority, retry_count
174 and clear successful and bootable bits.
175*/
176void partition_reset_attributes(unsigned index)
177{
178 struct partition_entry *partition_entries =
179 partition_get_partition_entries();
180
181 partition_entries[index].attribute_flag |= (PART_ATT_PRIORITY_VAL |
182 PART_ATT_MAX_RETRY_COUNT_VAL);
183
184 partition_entries[index].attribute_flag &= ((~PART_ATT_SUCCESSFUL_VAL) &
185 (~PART_ATT_UNBOOTABLE_VAL));
186
187 if (!attributes_updated)
188 attributes_updated = true;
189
190 /* Make attributes persistant */
191 partition_mark_active_slot(active_slot);
192}
193
194/*
195 Function: Switch active partitions.
196*/
197void partition_switch_slots(int old_slot, int new_slot)
198{
199#ifdef AB_DEBUG
200 dprintf(INFO, "Switching slots %s to %s\n",
201 SUFFIX_SLOT(old_slot), SUFFIX_SLOT(new_slot));
202#endif
203 struct partition_entry *partition_entries =
204 partition_get_partition_entries();
205 int old_slot_index = boot_slot_index[old_slot];
206 int new_slot_index = boot_slot_index[new_slot];
207
208 /* Mark current slot inactive, keeping all other attributes intact */
209 partition_entries[old_slot_index].attribute_flag &= ~PART_ATT_ACTIVE_VAL;
210
211 /* Mark new slot active */
212 partition_entries[new_slot_index].attribute_flag |=
213 ((PART_ATT_PRIORITY_VAL |
214 PART_ATT_ACTIVE_VAL |
215 PART_ATT_MAX_RETRY_COUNT_VAL));
216 partition_entries[new_slot_index].attribute_flag &=
217 (~PART_ATT_SUCCESSFUL_VAL
218 & ~PART_ATT_UNBOOTABLE_VAL);
219
220 if (!attributes_updated)
221 attributes_updated = true;
222
223 /* Update active slot and gpt table */
224 partition_mark_active_slot(new_slot);
225 return;
226}
227
228/*
229 This function returns the most priority and active slot,
230 also you need to update the global state seperately.
231
232*/
233int partition_find_active_slot()
234{
235 unsigned current_priority;
236 int i, count = 0;
237 bool current_bootable_bit;
238 bool current_active_bit;
239 unsigned boot_priority;
240 struct partition_entry *partition_entries = partition_get_partition_entries();
241
242 /* Return current active slot if already found */
243 if (active_slot != INVALID)
244 return active_slot;
245
246 for (boot_priority = MAX_PRIORITY;
247 boot_priority > 0; boot_priority--)
248 {
249 /* Search valid boot slot with highest priority */
250 for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
251 {
252 current_priority = slot_priority(partition_entries, boot_slot_index[i]);
253 current_active_bit = slot_is_active(partition_entries, boot_slot_index[i]);
254 current_bootable_bit = slot_is_bootable(partition_entries, boot_slot_index[i]);
255
256 /* Count number of slots with all attributes as zero */
257 if ( !current_priority &&
258 !current_active_bit &&
259 current_bootable_bit)
260 {
261 count ++;
262 continue;
263 }
264
265#ifdef AB_DEBUG
266 dprintf(INFO, "Slot:Priority:Active:Bootable %s:%d:%d:%d \n",
267 partition_entries[boot_slot_index[i]].name,
268 current_priority,
269 current_active_bit,
270 current_bootable_bit);
271#endif
272 if (boot_priority == current_priority)
273 {
274 if (current_active_bit &&
275 current_bootable_bit)
276 {
277#ifdef AB_DEBUG
278 dprintf(INFO, "Slot (%s) is Valid High Priority Slot\n", SUFFIX_SLOT(i));
279#endif
280 return i;
281 }
282 }
283 }
284
285 /* All slots are zeroed, this is first bootup */
286 /* Marking and trying SLOT 0 as default */
287 if (count == AB_SUPPORTED_SLOTS)
288 {
289 /* Update the priority of the boot slot */
290 partition_entries[boot_slot_index[SLOT_A]].attribute_flag |=
291 ((PART_ATT_PRIORITY_VAL |
292 PART_ATT_ACTIVE_VAL |
293 PART_ATT_MAX_RETRY_COUNT_VAL) &
294 (~PART_ATT_SUCCESSFUL_VAL &
295 ~PART_ATT_UNBOOTABLE_VAL));
296 if (!attributes_updated)
297 attributes_updated = true;
298 return SLOT_A;
299 }
300 }
301 /* If no valid slot */
302 return INVALID;
303}
304
305static int
306next_active_bootable_slot(struct partition_entry *ptn_entry)
307{
308 int i, slt_index;
309 for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
310 {
311 slt_index = boot_slot_index[i];
312 if (slot_is_bootable(ptn_entry, slt_index))
313 return i;
314 }
315
316 /* NO Bootable slot */
317 panic("ERROR: Unable to find any bootable slot");
318 return 0;
319}
320
321int partition_find_boot_slot()
322{
323 int boot_slot;
324 int slt_index;
325 uint64_t boot_retry_count;
326 struct partition_entry *partition_entries = partition_get_partition_entries();
327
328 boot_retry_count = 0;
329 boot_slot = partition_find_active_slot();
330
331 if (boot_slot == INVALID)
332 goto out;
333
334 slt_index = boot_slot_index[boot_slot];
335
336 /* Boot if partition flag is set to sucessful */
337 if (partition_entries[slt_index].attribute_flag & PART_ATT_SUCCESSFUL_VAL)
338 goto out;
339
340 boot_retry_count = slot_retry_count(partition_entries, slt_index);
341
342#ifdef AB_DEBUG
343 dprintf(INFO, "Boot Partition:RetryCount %s:%lld\n", partition_entries[slt_index].name,
344 boot_retry_count);
345#endif
346 if (!boot_retry_count)
347 {
348 /* Mark slot invalide and unbootable */
349 partition_entries[slt_index].attribute_flag |=
350 (PART_ATT_UNBOOTABLE_VAL &
351 ~PART_ATT_ACTIVE_VAL &
352 ~PART_ATT_PRIORITY_VAL);
353
354 partition_switch_slots(boot_slot, next_active_bootable_slot(partition_entries));
355
356 reboot_device(0);
357 }
358 else
359 {
360 /* Do normal boot */
361 /* Decrement retry count */
362 partition_entries[slt_index].attribute_flag =
363 (partition_entries[slt_index].attribute_flag
364 & ~PART_ATT_MAX_RETRY_COUNT_VAL)
365 | ((boot_retry_count-1) << PART_ATT_MAX_RETRY_CNT_BIT);
366
367 if (!attributes_updated)
368 attributes_updated = true;
369
370 goto out;
371 }
372
373out:
374#ifdef AB_DEBUG
375 dprintf(INFO, "Booting SLOT %d\n", boot_slot);
376#endif
377 return boot_slot;
378}
379
380static
381void guid_update(struct partition_entry *partition_entries,
382 unsigned old_index,
383 unsigned new_index)
384{
385 unsigned char tmp_guid[PARTITION_TYPE_GUID_SIZE];
386
387 memcpy(tmp_guid, partition_entries[old_index].type_guid,
388 PARTITION_TYPE_GUID_SIZE);
389 memcpy(partition_entries[old_index].type_guid,
390 partition_entries[new_index].type_guid,
391 PARTITION_TYPE_GUID_SIZE);
392 memcpy(partition_entries[new_index].type_guid, tmp_guid,
393 PARTITION_TYPE_GUID_SIZE);
394 return;
395}
396
397/*
398 Function to swap guids of slots
399*/
400static void
401swap_guid(int old_slot, int new_slot)
402{
403 unsigned i, j, tmp_strlen;
404 unsigned partition_cnt = partition_get_partition_count();
405 struct partition_entry *partition_entries =
406 partition_get_partition_entries();
407 const char *ptr_pname, *ptr_suffix;
408
409 if ( old_slot == new_slot)
410 return;
411
412 for(i = 0; i < partition_cnt; i++)
413 {
414 ptr_pname = (const char *)partition_entries[i].name;
415
416 /* Search for suffix in partition name */
417 if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(new_slot))))
418 {
419 for (j = i+1; j < partition_cnt; j++)
420 {
421 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(new_slot));
422 if (!strncmp((const char*)partition_entries[j].name, ptr_pname, tmp_strlen) &&
423 strstr((const char*)partition_entries[j].name, SUFFIX_SLOT(old_slot)))
424 guid_update(partition_entries, j, i);
425 }
426 }
427 else if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(old_slot))))
428 {
429 for (j = i+1; j < partition_cnt; j++)
430 {
431 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(old_slot));
432 if (!strncmp((const char *)partition_entries[j].name, ptr_pname, tmp_strlen) &&
433 strstr((const char *)partition_entries[j].name, SUFFIX_SLOT(new_slot)))
434 guid_update(partition_entries, i, j);
435 }
436 }
437 }
438}
439
440/*
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530441Function: To set active bit of all partitions of actve slot.
442 also, unset active bits of all other slot
443*/
444static void
445mark_all_partitions_active(signed slot)
446{
447 int i,j;
448 char *pname = NULL;
449 char *suffix_str = NULL;
450 struct partition_entry *partition_entries =
451 partition_get_partition_entries();
452 int partition_count = partition_get_partition_count();
453
454 for (i=0; i<partition_count; i++)
455 {
456 pname = (char *)partition_entries[i].name;
457 #ifdef AB_DEBUG
458 dprintf(INFO, "Transversing partition %s\n", pname);
459 #endif
460 /* 1. Find partition, if it is A/B enabled. */
461 for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
462 {
463 suffix_str = strstr(pname, SUFFIX_SLOT(j));
464 if (suffix_str)
465 break;
466 }
467
468 if (suffix_str)
469 {
470 if (!strcmp(suffix_str, SUFFIX_SLOT(slot)))
471 /* 2a. Mark matching partition as active. */
472 partition_entries[i].attribute_flag |= PART_ATT_ACTIVE_VAL;
473 else
474 /* 2b. Unset active bit for all other partitions. */
475 partition_entries[i].attribute_flag &= ~PART_ATT_ACTIVE_VAL;
476 }
477 }
478 attributes_updated = true;
479}
480
481/*
Mayank Grovered699202017-05-30 20:04:10 +0530482 Function: Mark the slot to be active and also conditionally
483 update the slot parameters if there is a change.
484*/
485void partition_mark_active_slot(signed slot)
486{
487 if (active_slot == slot)
488 goto out;
489
490 switch (active_slot)
491 {
492 case INVALID:
493 if (slot != SLOT_A)
494 swap_guid(SLOT_A, slot);
Mayank Grovered699202017-05-30 20:04:10 +0530495 default:
496 if (slot == INVALID)
497 swap_guid(active_slot, SLOT_A);
498 else
499 swap_guid(active_slot, slot);
500 }
501 active_slot = slot;
502out:
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530503 /* Set Active bit for all partitions of active slot */
504 mark_all_partitions_active(slot);
505
Mayank Grovered699202017-05-30 20:04:10 +0530506 if (attributes_updated)
507 attributes_update();
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530508
Mayank Grovered699202017-05-30 20:04:10 +0530509 return;
510}
511
512/* Function to find if multislot is supported */
513bool partition_multislot_is_supported()
514{
515 return multislot_support;
516}
517
518/*
519 Function to populate partition meta used
520 for fastboot get var info publication.
521
522 Input partition_entries, partition_count and
523 buffer to fill information.
524
525*/
526int partition_fill_partition_meta(char has_slot_pname[][MAX_GET_VAR_NAME_SIZE],
527 char has_slot_reply[][MAX_RSP_SIZE],
528 int array_size)
529{
530 int i,j,tmp;
531 int count = 0;
532 char *pname = NULL;
533 int pname_size;
534 struct partition_entry *partition_entries =
535 partition_get_partition_entries();
536 int partition_count = partition_get_partition_count();
537 char *suffix_str;
538
539 for (i=0; i<partition_count; i++)
540 {
541 pname = (char *)partition_entries[i].name;
542 pname_size = strlen(pname);
543 suffix_str = NULL;
544 #ifdef AB_DEBUG
545 dprintf(INFO, "Transversing partition %s\n", pname);
546 #endif
547 /* 1. Find partition, if it is A/B enabled. */
548 for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
549 {
550 suffix_str = strstr(pname, SUFFIX_SLOT(j));
551 if (suffix_str)
552 break;
553 }
554
555 if (suffix_str)
556 {
557 if (!strcmp(suffix_str, SUFFIX_SLOT(SLOT_A)))
558 {
559 /* 2. put the partition name in array */
560 tmp = pname_size-strlen(suffix_str);
561 strlcpy(has_slot_pname[count], pname, tmp+1);
Mayank Groverd22a1f52017-06-20 11:07:33 +0530562 strlcpy(has_slot_reply[count], " Yes", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530563 count++;
564 }
565 }
566 else
567 {
Mayank Groverd22a1f52017-06-20 11:07:33 +0530568 strlcpy(has_slot_pname[count], pname, MAX_GET_VAR_NAME_SIZE);
569 strlcpy(has_slot_reply[count], " No", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530570 count++;
571 }
572
573 /* Avoid over population of array provided */
574 if (count >= array_size)
575 {
576 dprintf(CRITICAL, "ERROR: Not able to parse all partitions\n");
577 return count;
578 }
579 }
580#ifdef AB_DEBUG
581 for (i=0; i<count; i++)
582 dprintf(INFO, "has-slot:%s:%s\n", has_slot_pname[i], has_slot_reply[i]);
583#endif
584 return count;
585}
586
587/*
588 Function to populate the slot meta used
589 for fastboot get var info publication.
590*/
591void partition_fill_slot_meta(struct ab_slot_info *slot_info)
592{
593 int i, current_slot_index;
594 struct partition_entry *ptn_entries = partition_get_partition_entries();
595 char buff[3];
596
597 /* Update slot info */
598 for(i=0; i<AB_SUPPORTED_SLOTS; i++)
599 {
600 current_slot_index = boot_slot_index[i];
Mayank Groverd22a1f52017-06-20 11:07:33 +0530601 strlcpy(slot_info[i].slot_is_unbootable_rsp,
602 slot_is_bootable(ptn_entries, current_slot_index)?"No":"Yes",
603 MAX_RSP_SIZE);
604 strlcpy(slot_info[i].slot_is_active_rsp,
605 slot_is_active(ptn_entries, current_slot_index)?"Yes":"No",
606 MAX_RSP_SIZE);
607 strlcpy(slot_info[i].slot_is_succesful_rsp,
608 slot_is_sucessful(ptn_entries, current_slot_index)?"Yes":"No",
609 MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530610 itoa(slot_retry_count(ptn_entries, current_slot_index),
611 (unsigned char *)buff, 2, 10);
Mayank Groverd22a1f52017-06-20 11:07:33 +0530612 strlcpy(slot_info[i].slot_retry_count_rsp, buff, MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530613 }
614}
615
616/*
617 Function to read and update the attributes of
618 GPT
619*/
620static int
621update_gpt(uint64_t gpt_start_addr,
622 uint64_t gpt_hdr_offset,
623 uint64_t gpt_entries_offset)
624{
625 char *buffer = NULL;
626 char *gpt_entries_ptr, *gpt_hdr_ptr, *tmp = NULL;
627 struct partition_entry *partition_entries = partition_get_partition_entries();
628 uint32_t partition_count = partition_get_partition_count();
629 unsigned i,max_partition_count = 0;
630 unsigned partition_entry_size = 0;
631 uint32_t block_size = mmc_get_device_blocksize();
632 uint32_t crc_val = 0;
633 int ret = 0;
634 uint64_t max_gpt_size_bytes =
635 (PARTITION_ENTRY_SIZE*NUM_PARTITIONS + GPT_HEADER_BLOCKS*block_size);
Mayank Grover9c866202017-06-29 17:48:55 +0530636 int lun = -1;
637
638 /* Get Current LUN for UFS target */
639 if (!platform_boot_dev_isemmc())
640 lun = mmc_get_lun();
Mayank Grovered699202017-05-30 20:04:10 +0530641
642 buffer = memalign(CACHE_LINE, ROUNDUP(max_gpt_size_bytes, CACHE_LINE));
Mayank Groverd22a1f52017-06-20 11:07:33 +0530643 if (!buffer)
644 {
645 dprintf(CRITICAL, "update_gpt: Failed at memory allocation\n");
646 goto out;
647 }
648
Mayank Grovered699202017-05-30 20:04:10 +0530649 ret = mmc_read(gpt_start_addr, (uint32_t *)buffer,
650 max_gpt_size_bytes);
651 if (ret)
652 {
653 dprintf(CRITICAL, "Failed to read GPT\n");
654 goto out;
655 }
656
657 /* 0. Intialise ptrs for header and entries */
658 gpt_entries_ptr = buffer + gpt_entries_offset*block_size;
659 gpt_hdr_ptr = buffer + gpt_hdr_offset*block_size;
660
661 /* 1. Update attributes_flag of partition entry */
662 tmp = gpt_entries_ptr;
663 for (i=0;i<partition_count;i++)
664 {
Mayank Grover9c866202017-06-29 17:48:55 +0530665 if (lun != -1)
666 {
667 /* Partition table is populated with entries from lun 0 to max lun.
668 * break out of the loop once we see the partition lun is > current lun */
669 if (partition_entries[i].lun > lun)
670 break;
671 /* Find the entry where the partition table for 'lun' starts
672 and then update the attributes */
673 if (partition_entries[i].lun != lun)
674 continue;
675 }
676
Mayank Grovered699202017-05-30 20:04:10 +0530677 /* Update the partition attributes */
678 PUT_LONG_LONG(&tmp[ATTRIBUTE_FLAG_OFFSET],
679 partition_entries[i].attribute_flag);
680 memscpy(tmp, PARTITION_TYPE_GUID_SIZE, partition_entries[i].type_guid,
681 PARTITION_TYPE_GUID_SIZE);
682
683 /* point to the next partition entry */
684 tmp += PARTITION_ENTRY_SIZE;
685 }
686
687 /* Calculate and update CRC of partition entries array */
688 max_partition_count =
689 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PARTITION_COUNT_OFFSET]);
690 partition_entry_size =
691 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PENTRY_SIZE_OFFSET]);
Kishor PK252e22c2017-08-30 17:26:43 +0530692
693 /* Check for partition entry size */
694 if (partition_entry_size != PARTITION_ENTRY_SIZE) {
695 dprintf(CRITICAL,"Invalid parition entry size\n");
696 goto out;
697 }
698
699 /* Check for maximum partition size */
700 if ((max_partition_count) > (MIN_PARTITION_ARRAY_SIZE /(partition_entry_size))) {
701 dprintf(CRITICAL, "Invalid maximum partition count\n");
702 goto out;
703 }
704
Mayank Grovered699202017-05-30 20:04:10 +0530705 crc_val = crc32(~0L, gpt_entries_ptr, ((max_partition_count) *
706 (partition_entry_size))) ^ (~0L);
707 PUT_LONG(&gpt_hdr_ptr[PARTITION_CRC_OFFSET], crc_val);
708
709
710 /* Write CRC to 0 before we calculate the crc of the GPT header */
711 crc_val = 0;
712 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
713 crc_val = crc32(~0L,gpt_hdr_ptr, GPT_HEADER_SIZE) ^ (~0L);
714 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
715
716 /* write to mmc */
717 ret = mmc_write(gpt_start_addr, max_gpt_size_bytes, buffer);
718 if (ret)
719 {
720 dprintf(CRITICAL, "Failed to write gpt\n");
721 goto out;
722 }
723out:
Mayank Groverd22a1f52017-06-20 11:07:33 +0530724 if (buffer)
725 free(buffer);
Mayank Grovered699202017-05-30 20:04:10 +0530726 return ret;
727}
728
729/**
730 Function to update the backup and primary gpt
731 partition.
732**/
733static void attributes_update()
734{
735 uint64_t offset;
736 uint64_t gpt_entries_offset, gpt_hdr_offset;
737 uint64_t gpt_start_addr;
738 int ret;
739 uint32_t block_size = mmc_get_device_blocksize();
740 unsigned max_entries_size_bytes = PARTITION_ENTRY_SIZE*NUM_PARTITIONS;
741 unsigned max_entries_blocks = max_entries_size_bytes/block_size;
742 unsigned max_gpt_blocks = GPT_HEADER_BLOCKS + max_entries_blocks;
Mayank Grover9c866202017-06-29 17:48:55 +0530743 int max_luns = 0, lun;
744 int cur_lun = mmc_get_lun();
Mayank Grovered699202017-05-30 20:04:10 +0530745
Mayank Grover9c866202017-06-29 17:48:55 +0530746#if defined(MMC_SDHCI_SUPPORT) || defined(UFS_SUPPORT)
747 if (platform_boot_dev_isemmc())
748 max_luns = 1;
749 else
750 max_luns = ufs_get_num_of_luns((struct ufs_dev*)target_mmc_device());
751#endif
752 for (lun = 0; lun < max_luns; lun++)
Mayank Grovered699202017-05-30 20:04:10 +0530753 {
Mayank Grover9c866202017-06-29 17:48:55 +0530754 /* Set current LUN */
755 mmc_set_lun(lun);
Mayank Grovered699202017-05-30 20:04:10 +0530756
Mayank Grover9c866202017-06-29 17:48:55 +0530757 /* Update Primary GPT */
758 offset = 0x01; /* offset is 0x1 for primary GPT */
759 gpt_start_addr = offset*block_size;
760 /* Take gpt_start_addr as start and calculate offset from that in block sz*/
761 gpt_hdr_offset = 0; /* For primary partition offset is zero */
762 gpt_entries_offset = GPT_HEADER_BLOCKS;
Mayank Grovered699202017-05-30 20:04:10 +0530763
Mayank Grover9c866202017-06-29 17:48:55 +0530764 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
765 if (ret)
766 {
767 dprintf(CRITICAL, "Failed to update Primary GPT\n");
768 return;
769 }
770
771 /* Update Secondary GPT */
772 offset = ((mmc_get_device_capacity()/block_size) - max_gpt_blocks);
773 gpt_start_addr = offset*block_size;
774 gpt_hdr_offset = max_entries_blocks;
775 gpt_entries_offset = 0; /* For secondary GPT entries offset is zero */
776
777 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
778 if (ret)
779 {
780 dprintf(CRITICAL, "Failed to update Secondary GPT\n");
781 return;
782 }
Mayank Grovered699202017-05-30 20:04:10 +0530783 }
Mayank Grover9c866202017-06-29 17:48:55 +0530784 mmc_set_lun(cur_lun);
Mayank Grovered699202017-05-30 20:04:10 +0530785 return;
786}