blob: 9784481f8b102a8c12235e77b428d872a59bb39c [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();
Mayank Grover0a20b6a2017-10-11 17:59:17 +053056static void mark_all_partitions_active(signed slot);
Mayank Grovered699202017-05-30 20:04:10 +053057/*
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
Mayank Groverff4587e2017-09-25 17:42:09 +0530242#ifdef AB_DEBUG
243 dprintf(INFO, "partition_find_active_slot() called\n");
244#endif
Mayank Grovered699202017-05-30 20:04:10 +0530245 /* Return current active slot if already found */
246 if (active_slot != INVALID)
Mayank Groverff4587e2017-09-25 17:42:09 +0530247 goto out;
Mayank Grovered699202017-05-30 20:04:10 +0530248
249 for (boot_priority = MAX_PRIORITY;
250 boot_priority > 0; boot_priority--)
251 {
252 /* Search valid boot slot with highest priority */
253 for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
254 {
255 current_priority = slot_priority(partition_entries, boot_slot_index[i]);
256 current_active_bit = slot_is_active(partition_entries, boot_slot_index[i]);
257 current_bootable_bit = slot_is_bootable(partition_entries, boot_slot_index[i]);
258
259 /* Count number of slots with all attributes as zero */
260 if ( !current_priority &&
261 !current_active_bit &&
262 current_bootable_bit)
263 {
264 count ++;
265 continue;
266 }
267
268#ifdef AB_DEBUG
269 dprintf(INFO, "Slot:Priority:Active:Bootable %s:%d:%d:%d \n",
270 partition_entries[boot_slot_index[i]].name,
271 current_priority,
272 current_active_bit,
273 current_bootable_bit);
274#endif
275 if (boot_priority == current_priority)
276 {
277 if (current_active_bit &&
278 current_bootable_bit)
279 {
280#ifdef AB_DEBUG
281 dprintf(INFO, "Slot (%s) is Valid High Priority Slot\n", SUFFIX_SLOT(i));
282#endif
Mayank Groverff4587e2017-09-25 17:42:09 +0530283 active_slot = i;
284 goto out;
Mayank Grovered699202017-05-30 20:04:10 +0530285 }
286 }
287 }
288
289 /* All slots are zeroed, this is first bootup */
290 /* Marking and trying SLOT 0 as default */
291 if (count == AB_SUPPORTED_SLOTS)
292 {
293 /* Update the priority of the boot slot */
294 partition_entries[boot_slot_index[SLOT_A]].attribute_flag |=
295 ((PART_ATT_PRIORITY_VAL |
296 PART_ATT_ACTIVE_VAL |
297 PART_ATT_MAX_RETRY_COUNT_VAL) &
298 (~PART_ATT_SUCCESSFUL_VAL &
299 ~PART_ATT_UNBOOTABLE_VAL));
Mayank Groverff4587e2017-09-25 17:42:09 +0530300
301 active_slot = SLOT_A;
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530302
Mayank Groverff4587e2017-09-25 17:42:09 +0530303 /* This is required to mark all bits as active,
304 for fresh boot post fresh flash */
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530305 mark_all_partitions_active(active_slot);
Mayank Groverff4587e2017-09-25 17:42:09 +0530306 goto out;
Mayank Grovered699202017-05-30 20:04:10 +0530307 }
308 }
Mayank Groverff4587e2017-09-25 17:42:09 +0530309out:
310 return active_slot;
Mayank Grovered699202017-05-30 20:04:10 +0530311}
312
313static int
314next_active_bootable_slot(struct partition_entry *ptn_entry)
315{
316 int i, slt_index;
317 for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
318 {
319 slt_index = boot_slot_index[i];
320 if (slot_is_bootable(ptn_entry, slt_index))
321 return i;
322 }
323
324 /* NO Bootable slot */
325 panic("ERROR: Unable to find any bootable slot");
326 return 0;
327}
328
329int partition_find_boot_slot()
330{
331 int boot_slot;
332 int slt_index;
333 uint64_t boot_retry_count;
334 struct partition_entry *partition_entries = partition_get_partition_entries();
335
336 boot_retry_count = 0;
337 boot_slot = partition_find_active_slot();
338
339 if (boot_slot == INVALID)
340 goto out;
341
342 slt_index = boot_slot_index[boot_slot];
343
344 /* Boot if partition flag is set to sucessful */
345 if (partition_entries[slt_index].attribute_flag & PART_ATT_SUCCESSFUL_VAL)
346 goto out;
347
348 boot_retry_count = slot_retry_count(partition_entries, slt_index);
349
350#ifdef AB_DEBUG
351 dprintf(INFO, "Boot Partition:RetryCount %s:%lld\n", partition_entries[slt_index].name,
352 boot_retry_count);
353#endif
354 if (!boot_retry_count)
355 {
356 /* Mark slot invalide and unbootable */
357 partition_entries[slt_index].attribute_flag |=
358 (PART_ATT_UNBOOTABLE_VAL &
359 ~PART_ATT_ACTIVE_VAL &
360 ~PART_ATT_PRIORITY_VAL);
361
362 partition_switch_slots(boot_slot, next_active_bootable_slot(partition_entries));
363
364 reboot_device(0);
365 }
366 else
367 {
368 /* Do normal boot */
369 /* Decrement retry count */
370 partition_entries[slt_index].attribute_flag =
371 (partition_entries[slt_index].attribute_flag
372 & ~PART_ATT_MAX_RETRY_COUNT_VAL)
373 | ((boot_retry_count-1) << PART_ATT_MAX_RETRY_CNT_BIT);
374
375 if (!attributes_updated)
376 attributes_updated = true;
377
378 goto out;
379 }
380
381out:
382#ifdef AB_DEBUG
383 dprintf(INFO, "Booting SLOT %d\n", boot_slot);
384#endif
385 return boot_slot;
386}
387
388static
389void guid_update(struct partition_entry *partition_entries,
390 unsigned old_index,
391 unsigned new_index)
392{
393 unsigned char tmp_guid[PARTITION_TYPE_GUID_SIZE];
394
Mayank Groverff4587e2017-09-25 17:42:09 +0530395#ifdef AB_DEBUG
396 dprintf(INFO, "Swapping GUID (%s) --> (%s) \n",
397 partition_entries[old_index].name,
398 partition_entries[new_index].name);
399#endif
Mayank Grovered699202017-05-30 20:04:10 +0530400 memcpy(tmp_guid, partition_entries[old_index].type_guid,
401 PARTITION_TYPE_GUID_SIZE);
402 memcpy(partition_entries[old_index].type_guid,
403 partition_entries[new_index].type_guid,
404 PARTITION_TYPE_GUID_SIZE);
405 memcpy(partition_entries[new_index].type_guid, tmp_guid,
406 PARTITION_TYPE_GUID_SIZE);
407 return;
408}
409
410/*
411 Function to swap guids of slots
412*/
413static void
414swap_guid(int old_slot, int new_slot)
415{
416 unsigned i, j, tmp_strlen;
417 unsigned partition_cnt = partition_get_partition_count();
418 struct partition_entry *partition_entries =
419 partition_get_partition_entries();
420 const char *ptr_pname, *ptr_suffix;
421
422 if ( old_slot == new_slot)
423 return;
424
425 for(i = 0; i < partition_cnt; i++)
426 {
427 ptr_pname = (const char *)partition_entries[i].name;
428
429 /* Search for suffix in partition name */
430 if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(new_slot))))
431 {
432 for (j = i+1; j < partition_cnt; j++)
433 {
434 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(new_slot));
435 if (!strncmp((const char*)partition_entries[j].name, ptr_pname, tmp_strlen) &&
436 strstr((const char*)partition_entries[j].name, SUFFIX_SLOT(old_slot)))
437 guid_update(partition_entries, j, i);
438 }
439 }
440 else if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(old_slot))))
441 {
442 for (j = i+1; j < partition_cnt; j++)
443 {
444 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(old_slot));
445 if (!strncmp((const char *)partition_entries[j].name, ptr_pname, tmp_strlen) &&
446 strstr((const char *)partition_entries[j].name, SUFFIX_SLOT(new_slot)))
447 guid_update(partition_entries, i, j);
448 }
449 }
450 }
451}
452
453/*
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530454Function: To set active bit of all partitions of actve slot.
455 also, unset active bits of all other slot
456*/
457static void
458mark_all_partitions_active(signed slot)
459{
460 int i,j;
461 char *pname = NULL;
462 char *suffix_str = NULL;
463 struct partition_entry *partition_entries =
464 partition_get_partition_entries();
465 int partition_count = partition_get_partition_count();
466
467 for (i=0; i<partition_count; i++)
468 {
469 pname = (char *)partition_entries[i].name;
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530470#ifdef AB_DEBUG
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530471 dprintf(INFO, "Transversing partition %s\n", pname);
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530472#endif
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530473 /* 1. Find partition, if it is A/B enabled. */
474 for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
475 {
476 suffix_str = strstr(pname, SUFFIX_SLOT(j));
477 if (suffix_str)
478 break;
479 }
480
481 if (suffix_str)
482 {
483 if (!strcmp(suffix_str, SUFFIX_SLOT(slot)))
484 /* 2a. Mark matching partition as active. */
485 partition_entries[i].attribute_flag |= PART_ATT_ACTIVE_VAL;
486 else
487 /* 2b. Unset active bit for all other partitions. */
488 partition_entries[i].attribute_flag &= ~PART_ATT_ACTIVE_VAL;
489 }
490 }
491 attributes_updated = true;
492}
493
494/*
Mayank Grovered699202017-05-30 20:04:10 +0530495 Function: Mark the slot to be active and also conditionally
496 update the slot parameters if there is a change.
497*/
498void partition_mark_active_slot(signed slot)
499{
500 if (active_slot == slot)
501 goto out;
502
Mayank Groverff4587e2017-09-25 17:42:09 +0530503 if(slot != INVALID)
Mayank Grovered699202017-05-30 20:04:10 +0530504 {
Mayank Groverff4587e2017-09-25 17:42:09 +0530505 dprintf(INFO, "Marking (%s) as active\n", SUFFIX_SLOT(slot));
506
507 /* 1. Swap GUID's to new slot */
508 swap_guid(active_slot, slot);
509
510 /* 2. Set Active bit for all partitions of active slot */
511 mark_all_partitions_active(slot);
Mayank Grovered699202017-05-30 20:04:10 +0530512 }
Mayank Groverff4587e2017-09-25 17:42:09 +0530513
Mayank Grovered699202017-05-30 20:04:10 +0530514 active_slot = slot;
515out:
516 if (attributes_updated)
517 attributes_update();
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530518
Mayank Grovered699202017-05-30 20:04:10 +0530519 return;
520}
521
522/* Function to find if multislot is supported */
523bool partition_multislot_is_supported()
524{
525 return multislot_support;
526}
527
528/*
529 Function to populate partition meta used
530 for fastboot get var info publication.
531
532 Input partition_entries, partition_count and
533 buffer to fill information.
534
535*/
536int partition_fill_partition_meta(char has_slot_pname[][MAX_GET_VAR_NAME_SIZE],
537 char has_slot_reply[][MAX_RSP_SIZE],
538 int array_size)
539{
540 int i,j,tmp;
541 int count = 0;
542 char *pname = NULL;
543 int pname_size;
544 struct partition_entry *partition_entries =
545 partition_get_partition_entries();
546 int partition_count = partition_get_partition_count();
547 char *suffix_str;
548
549 for (i=0; i<partition_count; i++)
550 {
551 pname = (char *)partition_entries[i].name;
552 pname_size = strlen(pname);
553 suffix_str = NULL;
554 #ifdef AB_DEBUG
555 dprintf(INFO, "Transversing partition %s\n", pname);
556 #endif
557 /* 1. Find partition, if it is A/B enabled. */
558 for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
559 {
560 suffix_str = strstr(pname, SUFFIX_SLOT(j));
561 if (suffix_str)
562 break;
563 }
564
565 if (suffix_str)
566 {
567 if (!strcmp(suffix_str, SUFFIX_SLOT(SLOT_A)))
568 {
569 /* 2. put the partition name in array */
570 tmp = pname_size-strlen(suffix_str);
571 strlcpy(has_slot_pname[count], pname, tmp+1);
Mayank Groverd22a1f52017-06-20 11:07:33 +0530572 strlcpy(has_slot_reply[count], " Yes", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530573 count++;
574 }
575 }
576 else
577 {
Mayank Groverd22a1f52017-06-20 11:07:33 +0530578 strlcpy(has_slot_pname[count], pname, MAX_GET_VAR_NAME_SIZE);
579 strlcpy(has_slot_reply[count], " No", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530580 count++;
581 }
582
583 /* Avoid over population of array provided */
584 if (count >= array_size)
585 {
586 dprintf(CRITICAL, "ERROR: Not able to parse all partitions\n");
587 return count;
588 }
589 }
590#ifdef AB_DEBUG
591 for (i=0; i<count; i++)
592 dprintf(INFO, "has-slot:%s:%s\n", has_slot_pname[i], has_slot_reply[i]);
593#endif
594 return count;
595}
596
597/*
598 Function to populate the slot meta used
599 for fastboot get var info publication.
600*/
601void partition_fill_slot_meta(struct ab_slot_info *slot_info)
602{
603 int i, current_slot_index;
604 struct partition_entry *ptn_entries = partition_get_partition_entries();
605 char buff[3];
606
607 /* Update slot info */
608 for(i=0; i<AB_SUPPORTED_SLOTS; i++)
609 {
610 current_slot_index = boot_slot_index[i];
Mayank Groverd22a1f52017-06-20 11:07:33 +0530611 strlcpy(slot_info[i].slot_is_unbootable_rsp,
612 slot_is_bootable(ptn_entries, current_slot_index)?"No":"Yes",
613 MAX_RSP_SIZE);
614 strlcpy(slot_info[i].slot_is_active_rsp,
615 slot_is_active(ptn_entries, current_slot_index)?"Yes":"No",
616 MAX_RSP_SIZE);
617 strlcpy(slot_info[i].slot_is_succesful_rsp,
618 slot_is_sucessful(ptn_entries, current_slot_index)?"Yes":"No",
619 MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530620 itoa(slot_retry_count(ptn_entries, current_slot_index),
621 (unsigned char *)buff, 2, 10);
Mayank Groverd22a1f52017-06-20 11:07:33 +0530622 strlcpy(slot_info[i].slot_retry_count_rsp, buff, MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530623 }
624}
625
626/*
627 Function to read and update the attributes of
628 GPT
629*/
630static int
631update_gpt(uint64_t gpt_start_addr,
632 uint64_t gpt_hdr_offset,
633 uint64_t gpt_entries_offset)
634{
635 char *buffer = NULL;
636 char *gpt_entries_ptr, *gpt_hdr_ptr, *tmp = NULL;
637 struct partition_entry *partition_entries = partition_get_partition_entries();
638 uint32_t partition_count = partition_get_partition_count();
639 unsigned i,max_partition_count = 0;
640 unsigned partition_entry_size = 0;
641 uint32_t block_size = mmc_get_device_blocksize();
642 uint32_t crc_val = 0;
643 int ret = 0;
644 uint64_t max_gpt_size_bytes =
645 (PARTITION_ENTRY_SIZE*NUM_PARTITIONS + GPT_HEADER_BLOCKS*block_size);
Mayank Grover9c866202017-06-29 17:48:55 +0530646 int lun = -1;
647
648 /* Get Current LUN for UFS target */
649 if (!platform_boot_dev_isemmc())
650 lun = mmc_get_lun();
Mayank Grovered699202017-05-30 20:04:10 +0530651
652 buffer = memalign(CACHE_LINE, ROUNDUP(max_gpt_size_bytes, CACHE_LINE));
Mayank Groverd22a1f52017-06-20 11:07:33 +0530653 if (!buffer)
654 {
655 dprintf(CRITICAL, "update_gpt: Failed at memory allocation\n");
656 goto out;
657 }
658
Mayank Grovered699202017-05-30 20:04:10 +0530659 ret = mmc_read(gpt_start_addr, (uint32_t *)buffer,
660 max_gpt_size_bytes);
661 if (ret)
662 {
663 dprintf(CRITICAL, "Failed to read GPT\n");
664 goto out;
665 }
666
667 /* 0. Intialise ptrs for header and entries */
668 gpt_entries_ptr = buffer + gpt_entries_offset*block_size;
669 gpt_hdr_ptr = buffer + gpt_hdr_offset*block_size;
670
671 /* 1. Update attributes_flag of partition entry */
672 tmp = gpt_entries_ptr;
673 for (i=0;i<partition_count;i++)
674 {
Mayank Grover9c866202017-06-29 17:48:55 +0530675 if (lun != -1)
676 {
677 /* Partition table is populated with entries from lun 0 to max lun.
678 * break out of the loop once we see the partition lun is > current lun */
679 if (partition_entries[i].lun > lun)
680 break;
681 /* Find the entry where the partition table for 'lun' starts
682 and then update the attributes */
683 if (partition_entries[i].lun != lun)
684 continue;
685 }
686
Mayank Grovered699202017-05-30 20:04:10 +0530687 /* Update the partition attributes */
688 PUT_LONG_LONG(&tmp[ATTRIBUTE_FLAG_OFFSET],
689 partition_entries[i].attribute_flag);
690 memscpy(tmp, PARTITION_TYPE_GUID_SIZE, partition_entries[i].type_guid,
691 PARTITION_TYPE_GUID_SIZE);
692
693 /* point to the next partition entry */
694 tmp += PARTITION_ENTRY_SIZE;
695 }
696
697 /* Calculate and update CRC of partition entries array */
698 max_partition_count =
699 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PARTITION_COUNT_OFFSET]);
700 partition_entry_size =
701 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PENTRY_SIZE_OFFSET]);
Kishor PK252e22c2017-08-30 17:26:43 +0530702
703 /* Check for partition entry size */
704 if (partition_entry_size != PARTITION_ENTRY_SIZE) {
705 dprintf(CRITICAL,"Invalid parition entry size\n");
706 goto out;
707 }
708
709 /* Check for maximum partition size */
710 if ((max_partition_count) > (MIN_PARTITION_ARRAY_SIZE /(partition_entry_size))) {
711 dprintf(CRITICAL, "Invalid maximum partition count\n");
712 goto out;
713 }
714
Mayank Grovered699202017-05-30 20:04:10 +0530715 crc_val = crc32(~0L, gpt_entries_ptr, ((max_partition_count) *
716 (partition_entry_size))) ^ (~0L);
717 PUT_LONG(&gpt_hdr_ptr[PARTITION_CRC_OFFSET], crc_val);
718
719
720 /* Write CRC to 0 before we calculate the crc of the GPT header */
721 crc_val = 0;
722 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
723 crc_val = crc32(~0L,gpt_hdr_ptr, GPT_HEADER_SIZE) ^ (~0L);
724 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
725
726 /* write to mmc */
727 ret = mmc_write(gpt_start_addr, max_gpt_size_bytes, buffer);
728 if (ret)
729 {
730 dprintf(CRITICAL, "Failed to write gpt\n");
731 goto out;
732 }
733out:
Mayank Groverd22a1f52017-06-20 11:07:33 +0530734 if (buffer)
735 free(buffer);
Mayank Grovered699202017-05-30 20:04:10 +0530736 return ret;
737}
738
739/**
740 Function to update the backup and primary gpt
741 partition.
742**/
743static void attributes_update()
744{
745 uint64_t offset;
746 uint64_t gpt_entries_offset, gpt_hdr_offset;
747 uint64_t gpt_start_addr;
748 int ret;
749 uint32_t block_size = mmc_get_device_blocksize();
750 unsigned max_entries_size_bytes = PARTITION_ENTRY_SIZE*NUM_PARTITIONS;
751 unsigned max_entries_blocks = max_entries_size_bytes/block_size;
752 unsigned max_gpt_blocks = GPT_HEADER_BLOCKS + max_entries_blocks;
Mayank Grover9c866202017-06-29 17:48:55 +0530753 int max_luns = 0, lun;
754 int cur_lun = mmc_get_lun();
Mayank Grovered699202017-05-30 20:04:10 +0530755
Mayank Grover9c866202017-06-29 17:48:55 +0530756#if defined(MMC_SDHCI_SUPPORT) || defined(UFS_SUPPORT)
757 if (platform_boot_dev_isemmc())
758 max_luns = 1;
759 else
760 max_luns = ufs_get_num_of_luns((struct ufs_dev*)target_mmc_device());
761#endif
762 for (lun = 0; lun < max_luns; lun++)
Mayank Grovered699202017-05-30 20:04:10 +0530763 {
Mayank Grover9c866202017-06-29 17:48:55 +0530764 /* Set current LUN */
765 mmc_set_lun(lun);
Mayank Grovered699202017-05-30 20:04:10 +0530766
Mayank Grover9c866202017-06-29 17:48:55 +0530767 /* Update Primary GPT */
768 offset = 0x01; /* offset is 0x1 for primary GPT */
769 gpt_start_addr = offset*block_size;
770 /* Take gpt_start_addr as start and calculate offset from that in block sz*/
771 gpt_hdr_offset = 0; /* For primary partition offset is zero */
772 gpt_entries_offset = GPT_HEADER_BLOCKS;
Mayank Grovered699202017-05-30 20:04:10 +0530773
Mayank Grover9c866202017-06-29 17:48:55 +0530774 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
775 if (ret)
776 {
777 dprintf(CRITICAL, "Failed to update Primary GPT\n");
778 return;
779 }
780
781 /* Update Secondary GPT */
782 offset = ((mmc_get_device_capacity()/block_size) - max_gpt_blocks);
783 gpt_start_addr = offset*block_size;
784 gpt_hdr_offset = max_entries_blocks;
785 gpt_entries_offset = 0; /* For secondary GPT entries offset is zero */
786
787 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
788 if (ret)
789 {
790 dprintf(CRITICAL, "Failed to update Secondary GPT\n");
791 return;
792 }
Mayank Grovered699202017-05-30 20:04:10 +0530793 }
Mayank Grover9c866202017-06-29 17:48:55 +0530794 mmc_set_lun(cur_lun);
Mayank Grovered699202017-05-30 20:04:10 +0530795 return;
796}