blob: 64e259ce9d916708a45e38f85a99af480d12efcb [file] [log] [blame]
Mayank Grovered699202017-05-30 20:04:10 +05301/*
lijuang165fcbb2019-07-05 17:50:06 +08002 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
Mayank Grovered699202017-05-30 20:04:10 +05303 *
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
Mayank Groverc2ccc682017-10-24 19:02:49 +0530105void
106partition_deactivate_slot(int slot)
107{
108 struct partition_entry *partition_entries =
109 partition_get_partition_entries();
110 int slt_index = boot_slot_index[slot];
111
112 /* Set Unbootable bit */
113 SET_BIT(partition_entries[slt_index].attribute_flag, PART_ATT_UNBOOTABLE_BIT);
114
115 /* Clear Sucess bit and Active bits */
116 CLR_BIT(partition_entries[slt_index].attribute_flag, PART_ATT_SUCCESS_BIT);
117 CLR_BIT(partition_entries[slt_index].attribute_flag, PART_ATT_ACTIVE_BIT);
118
119 /* Clear Max retry count and priority value */
120 partition_entries[slt_index].attribute_flag &= (~PART_ATT_PRIORITY_VAL &
121 ~PART_ATT_MAX_RETRY_COUNT_VAL);
122
123 return;
124}
125
126void
127partition_activate_slot(int slot)
128{
129 struct partition_entry *partition_entries =
130 partition_get_partition_entries();
131 int slt_index = boot_slot_index[slot];
132
133 /* CLR Unbootable bit and Sucess bit*/
134 CLR_BIT(partition_entries[slt_index].attribute_flag, PART_ATT_UNBOOTABLE_BIT);
135 CLR_BIT(partition_entries[slt_index].attribute_flag, PART_ATT_SUCCESS_BIT);
136
137 /* Set Active bits */
138 SET_BIT(partition_entries[slt_index].attribute_flag, PART_ATT_ACTIVE_BIT);
139
140 /* Set Max retry count and priority value */
141 partition_entries[slt_index].attribute_flag |= (PART_ATT_PRIORITY_VAL |
142 PART_ATT_MAX_RETRY_COUNT_VAL);
143
144 return;
145}
146
Mayank Grovered699202017-05-30 20:04:10 +0530147/*
148 Function scan boot partition to find SLOT_A/SLOT_B suffix.
149 If found than make multislot_boot flag true and
150 scans another partition.
151*/
152bool partition_scan_for_multislot()
153{
154 int i, j, count = 0;
155 char *pname = NULL;
156 int strlen_boot = strlen("boot");
157 int partition_count = partition_get_partition_count();
158 struct partition_entry *partition_entries =
159 partition_get_partition_entries();
160
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530161 /* Intialize all slot specific variables */
Mayank Grovered699202017-05-30 20:04:10 +0530162 multislot_support = false;
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530163 active_slot = INVALID;
164 attributes_updated = false;
Mayank Grovered699202017-05-30 20:04:10 +0530165
166 if (partition_count > NUM_PARTITIONS)
167 {
168 dprintf(CRITICAL, "ERROR: partition_count more than supported.\n");
169 return multislot_support;
170 }
171
172 for (i = 0; i < partition_count; i++)
173 {
174 pname = (char *)partition_entries[i].name;
175#ifdef AB_DEBUG
176 dprintf(INFO, "Transversing partition %s\n", pname);
177#endif
178 if (!strncmp((const char *)partition_entries[i].name, "boot", strlen_boot))
179 {
180 pname += strlen_boot;
181 if (*pname)
182 {
183#ifdef AB_DEBUG
184 dprintf(INFO, "Suffix: %s\n", pname);
185#endif
186 for (j =0; j<AB_SUPPORTED_SLOTS; j++)
187 {
188 if (!strcmp(pname, suffix_slot[j]))
189 {
190 /* cache these variables as they are used multiple times */
191 boot_slot_index[j] = i;
192 if (!multislot_support)
193 multislot_support =true;
194 count ++;
195 }
196 }
197 /* Break out of loop if all slot index are found*/
198 if (count == AB_SUPPORTED_SLOTS)
199 break;
200 }
201 else
202 {
203#ifdef AB_DEBUG
204 dprintf(INFO, "Partition Table is not a/b supported\n");
205#endif
206 break;
207 }
208 }
209 }
210 return multislot_support;
211}
212
213/*
214 Function: To reset partition attributes
215 This function reset partition_priority, retry_count
216 and clear successful and bootable bits.
217*/
218void partition_reset_attributes(unsigned index)
219{
220 struct partition_entry *partition_entries =
221 partition_get_partition_entries();
222
223 partition_entries[index].attribute_flag |= (PART_ATT_PRIORITY_VAL |
224 PART_ATT_MAX_RETRY_COUNT_VAL);
225
226 partition_entries[index].attribute_flag &= ((~PART_ATT_SUCCESSFUL_VAL) &
227 (~PART_ATT_UNBOOTABLE_VAL));
228
229 if (!attributes_updated)
230 attributes_updated = true;
231
232 /* Make attributes persistant */
233 partition_mark_active_slot(active_slot);
234}
235
236/*
237 Function: Switch active partitions.
238*/
lijuang165fcbb2019-07-05 17:50:06 +0800239void partition_switch_slots(int old_slot, int new_slot, boolean reset_success_bit)
Mayank Grovered699202017-05-30 20:04:10 +0530240{
241#ifdef AB_DEBUG
242 dprintf(INFO, "Switching slots %s to %s\n",
243 SUFFIX_SLOT(old_slot), SUFFIX_SLOT(new_slot));
244#endif
245 struct partition_entry *partition_entries =
246 partition_get_partition_entries();
247 int old_slot_index = boot_slot_index[old_slot];
248 int new_slot_index = boot_slot_index[new_slot];
249
250 /* Mark current slot inactive, keeping all other attributes intact */
251 partition_entries[old_slot_index].attribute_flag &= ~PART_ATT_ACTIVE_VAL;
252
253 /* Mark new slot active */
254 partition_entries[new_slot_index].attribute_flag |=
255 ((PART_ATT_PRIORITY_VAL |
256 PART_ATT_ACTIVE_VAL |
257 PART_ATT_MAX_RETRY_COUNT_VAL));
lijuang165fcbb2019-07-05 17:50:06 +0800258
Mayank Grovered699202017-05-30 20:04:10 +0530259 partition_entries[new_slot_index].attribute_flag &=
lijuang165fcbb2019-07-05 17:50:06 +0800260 (~PART_ATT_UNBOOTABLE_VAL);
261 if (reset_success_bit &&
262 (partition_entries[new_slot_index].attribute_flag &
263 PART_ATT_SUCCESSFUL_VAL)) {
264 partition_entries[new_slot_index].attribute_flag &=
265 (~PART_ATT_SUCCESSFUL_VAL);
266 }
Mayank Grovered699202017-05-30 20:04:10 +0530267
268 if (!attributes_updated)
269 attributes_updated = true;
270
271 /* Update active slot and gpt table */
272 partition_mark_active_slot(new_slot);
273 return;
274}
275
276/*
277 This function returns the most priority and active slot,
278 also you need to update the global state seperately.
279
280*/
281int partition_find_active_slot()
282{
283 unsigned current_priority;
284 int i, count = 0;
285 bool current_bootable_bit;
286 bool current_active_bit;
287 unsigned boot_priority;
288 struct partition_entry *partition_entries = partition_get_partition_entries();
289
Mayank Groverff4587e2017-09-25 17:42:09 +0530290#ifdef AB_DEBUG
291 dprintf(INFO, "partition_find_active_slot() called\n");
292#endif
Mayank Grovered699202017-05-30 20:04:10 +0530293 /* Return current active slot if already found */
294 if (active_slot != INVALID)
Mayank Groverff4587e2017-09-25 17:42:09 +0530295 goto out;
Mayank Grovered699202017-05-30 20:04:10 +0530296
297 for (boot_priority = MAX_PRIORITY;
298 boot_priority > 0; boot_priority--)
299 {
300 /* Search valid boot slot with highest priority */
301 for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
302 {
303 current_priority = slot_priority(partition_entries, boot_slot_index[i]);
304 current_active_bit = slot_is_active(partition_entries, boot_slot_index[i]);
305 current_bootable_bit = slot_is_bootable(partition_entries, boot_slot_index[i]);
306
307 /* Count number of slots with all attributes as zero */
308 if ( !current_priority &&
309 !current_active_bit &&
310 current_bootable_bit)
311 {
312 count ++;
313 continue;
314 }
315
316#ifdef AB_DEBUG
317 dprintf(INFO, "Slot:Priority:Active:Bootable %s:%d:%d:%d \n",
318 partition_entries[boot_slot_index[i]].name,
319 current_priority,
320 current_active_bit,
321 current_bootable_bit);
322#endif
323 if (boot_priority == current_priority)
324 {
325 if (current_active_bit &&
326 current_bootable_bit)
327 {
328#ifdef AB_DEBUG
329 dprintf(INFO, "Slot (%s) is Valid High Priority Slot\n", SUFFIX_SLOT(i));
330#endif
Mayank Groverff4587e2017-09-25 17:42:09 +0530331 active_slot = i;
332 goto out;
Mayank Grovered699202017-05-30 20:04:10 +0530333 }
334 }
335 }
336
337 /* All slots are zeroed, this is first bootup */
338 /* Marking and trying SLOT 0 as default */
339 if (count == AB_SUPPORTED_SLOTS)
340 {
341 /* Update the priority of the boot slot */
Mayank Groverc2ccc682017-10-24 19:02:49 +0530342 partition_activate_slot(SLOT_A);
Mayank Groverff4587e2017-09-25 17:42:09 +0530343
344 active_slot = SLOT_A;
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530345
Mayank Groverff4587e2017-09-25 17:42:09 +0530346 /* This is required to mark all bits as active,
347 for fresh boot post fresh flash */
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530348 mark_all_partitions_active(active_slot);
Mayank Groverff4587e2017-09-25 17:42:09 +0530349 goto out;
Mayank Grovered699202017-05-30 20:04:10 +0530350 }
351 }
Mayank Groverff4587e2017-09-25 17:42:09 +0530352out:
353 return active_slot;
Mayank Grovered699202017-05-30 20:04:10 +0530354}
355
356static int
357next_active_bootable_slot(struct partition_entry *ptn_entry)
358{
359 int i, slt_index;
360 for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
361 {
362 slt_index = boot_slot_index[i];
Rahul Shahareae2b7782021-04-26 16:16:15 +0530363 if (slot_is_bootable(ptn_entry, slt_index) &&
364 slot_is_sucessful(ptn_entry, slt_index))
Mayank Grovered699202017-05-30 20:04:10 +0530365 return i;
366 }
367
Mayank Groverbd8fdaa2018-01-25 13:04:54 +0530368 dprintf(CRITICAL, "ERROR: Unable to find any bootable slot");
369 return INVALID;
Mayank Grovered699202017-05-30 20:04:10 +0530370}
371
372int partition_find_boot_slot()
373{
Mayank Groverbd8fdaa2018-01-25 13:04:54 +0530374 int boot_slot, next_slot;
Mayank Grovered699202017-05-30 20:04:10 +0530375 int slt_index;
376 uint64_t boot_retry_count;
377 struct partition_entry *partition_entries = partition_get_partition_entries();
378
379 boot_retry_count = 0;
380 boot_slot = partition_find_active_slot();
381
382 if (boot_slot == INVALID)
383 goto out;
384
385 slt_index = boot_slot_index[boot_slot];
386
387 /* Boot if partition flag is set to sucessful */
388 if (partition_entries[slt_index].attribute_flag & PART_ATT_SUCCESSFUL_VAL)
389 goto out;
390
391 boot_retry_count = slot_retry_count(partition_entries, slt_index);
392
393#ifdef AB_DEBUG
394 dprintf(INFO, "Boot Partition:RetryCount %s:%lld\n", partition_entries[slt_index].name,
395 boot_retry_count);
396#endif
397 if (!boot_retry_count)
398 {
Mayank Groverc2ccc682017-10-24 19:02:49 +0530399 /* Mark slot invalid and unbootable */
400 partition_deactivate_slot(boot_slot);
Mayank Grovered699202017-05-30 20:04:10 +0530401
Mayank Groverbd8fdaa2018-01-25 13:04:54 +0530402 next_slot = next_active_bootable_slot(partition_entries);
403 if (next_slot != INVALID)
404 {
lijuang165fcbb2019-07-05 17:50:06 +0800405 partition_switch_slots(boot_slot, next_slot, false);
Mayank Groverbd8fdaa2018-01-25 13:04:54 +0530406 reboot_device(0);
407 }
408 else
409 {
410 boot_slot = INVALID;
411 }
Mayank Grovered699202017-05-30 20:04:10 +0530412 }
413 else
414 {
415 /* Do normal boot */
416 /* Decrement retry count */
417 partition_entries[slt_index].attribute_flag =
418 (partition_entries[slt_index].attribute_flag
419 & ~PART_ATT_MAX_RETRY_COUNT_VAL)
420 | ((boot_retry_count-1) << PART_ATT_MAX_RETRY_CNT_BIT);
421
422 if (!attributes_updated)
423 attributes_updated = true;
424
425 goto out;
426 }
427
428out:
429#ifdef AB_DEBUG
430 dprintf(INFO, "Booting SLOT %d\n", boot_slot);
431#endif
432 return boot_slot;
433}
434
435static
436void guid_update(struct partition_entry *partition_entries,
437 unsigned old_index,
438 unsigned new_index)
439{
440 unsigned char tmp_guid[PARTITION_TYPE_GUID_SIZE];
441
Mayank Groverff4587e2017-09-25 17:42:09 +0530442#ifdef AB_DEBUG
443 dprintf(INFO, "Swapping GUID (%s) --> (%s) \n",
444 partition_entries[old_index].name,
445 partition_entries[new_index].name);
446#endif
Mayank Grovered699202017-05-30 20:04:10 +0530447 memcpy(tmp_guid, partition_entries[old_index].type_guid,
448 PARTITION_TYPE_GUID_SIZE);
449 memcpy(partition_entries[old_index].type_guid,
450 partition_entries[new_index].type_guid,
451 PARTITION_TYPE_GUID_SIZE);
452 memcpy(partition_entries[new_index].type_guid, tmp_guid,
453 PARTITION_TYPE_GUID_SIZE);
454 return;
455}
456
457/*
458 Function to swap guids of slots
459*/
460static void
461swap_guid(int old_slot, int new_slot)
462{
463 unsigned i, j, tmp_strlen;
464 unsigned partition_cnt = partition_get_partition_count();
465 struct partition_entry *partition_entries =
466 partition_get_partition_entries();
467 const char *ptr_pname, *ptr_suffix;
468
469 if ( old_slot == new_slot)
470 return;
471
472 for(i = 0; i < partition_cnt; i++)
473 {
474 ptr_pname = (const char *)partition_entries[i].name;
475
476 /* Search for suffix in partition name */
477 if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(new_slot))))
478 {
479 for (j = i+1; j < partition_cnt; j++)
480 {
481 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(new_slot));
482 if (!strncmp((const char*)partition_entries[j].name, ptr_pname, tmp_strlen) &&
483 strstr((const char*)partition_entries[j].name, SUFFIX_SLOT(old_slot)))
484 guid_update(partition_entries, j, i);
485 }
486 }
487 else if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(old_slot))))
488 {
489 for (j = i+1; j < partition_cnt; j++)
490 {
491 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(old_slot));
492 if (!strncmp((const char *)partition_entries[j].name, ptr_pname, tmp_strlen) &&
493 strstr((const char *)partition_entries[j].name, SUFFIX_SLOT(new_slot)))
494 guid_update(partition_entries, i, j);
495 }
496 }
497 }
498}
499
500/*
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530501Function: To set active bit of all partitions of actve slot.
502 also, unset active bits of all other slot
503*/
504static void
505mark_all_partitions_active(signed slot)
506{
507 int i,j;
508 char *pname = NULL;
509 char *suffix_str = NULL;
510 struct partition_entry *partition_entries =
511 partition_get_partition_entries();
512 int partition_count = partition_get_partition_count();
513
514 for (i=0; i<partition_count; i++)
515 {
516 pname = (char *)partition_entries[i].name;
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530517#ifdef AB_DEBUG
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530518 dprintf(INFO, "Transversing partition %s\n", pname);
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530519#endif
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530520 /* 1. Find partition, if it is A/B enabled. */
521 for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
522 {
523 suffix_str = strstr(pname, SUFFIX_SLOT(j));
524 if (suffix_str)
525 break;
526 }
527
528 if (suffix_str)
529 {
530 if (!strcmp(suffix_str, SUFFIX_SLOT(slot)))
531 /* 2a. Mark matching partition as active. */
532 partition_entries[i].attribute_flag |= PART_ATT_ACTIVE_VAL;
533 else
534 /* 2b. Unset active bit for all other partitions. */
535 partition_entries[i].attribute_flag &= ~PART_ATT_ACTIVE_VAL;
536 }
537 }
538 attributes_updated = true;
539}
540
541/*
Mayank Grovered699202017-05-30 20:04:10 +0530542 Function: Mark the slot to be active and also conditionally
543 update the slot parameters if there is a change.
544*/
545void partition_mark_active_slot(signed slot)
546{
547 if (active_slot == slot)
548 goto out;
549
Mayank Groverff4587e2017-09-25 17:42:09 +0530550 if(slot != INVALID)
Mayank Grovered699202017-05-30 20:04:10 +0530551 {
Mayank Groverff4587e2017-09-25 17:42:09 +0530552 dprintf(INFO, "Marking (%s) as active\n", SUFFIX_SLOT(slot));
553
554 /* 1. Swap GUID's to new slot */
555 swap_guid(active_slot, slot);
556
557 /* 2. Set Active bit for all partitions of active slot */
558 mark_all_partitions_active(slot);
Mayank Grovered699202017-05-30 20:04:10 +0530559 }
Mayank Groverff4587e2017-09-25 17:42:09 +0530560
Mayank Grovered699202017-05-30 20:04:10 +0530561 active_slot = slot;
562out:
563 if (attributes_updated)
564 attributes_update();
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530565
Mayank Grovered699202017-05-30 20:04:10 +0530566 return;
567}
568
569/* Function to find if multislot is supported */
570bool partition_multislot_is_supported()
571{
572 return multislot_support;
573}
574
575/*
576 Function to populate partition meta used
577 for fastboot get var info publication.
578
579 Input partition_entries, partition_count and
580 buffer to fill information.
581
582*/
583int partition_fill_partition_meta(char has_slot_pname[][MAX_GET_VAR_NAME_SIZE],
584 char has_slot_reply[][MAX_RSP_SIZE],
585 int array_size)
586{
587 int i,j,tmp;
588 int count = 0;
589 char *pname = NULL;
590 int pname_size;
591 struct partition_entry *partition_entries =
592 partition_get_partition_entries();
593 int partition_count = partition_get_partition_count();
594 char *suffix_str;
595
596 for (i=0; i<partition_count; i++)
597 {
598 pname = (char *)partition_entries[i].name;
599 pname_size = strlen(pname);
600 suffix_str = NULL;
601 #ifdef AB_DEBUG
602 dprintf(INFO, "Transversing partition %s\n", pname);
603 #endif
604 /* 1. Find partition, if it is A/B enabled. */
605 for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
606 {
607 suffix_str = strstr(pname, SUFFIX_SLOT(j));
608 if (suffix_str)
609 break;
610 }
611
612 if (suffix_str)
613 {
614 if (!strcmp(suffix_str, SUFFIX_SLOT(SLOT_A)))
615 {
616 /* 2. put the partition name in array */
617 tmp = pname_size-strlen(suffix_str);
618 strlcpy(has_slot_pname[count], pname, tmp+1);
Luca Weiss5e78d652022-03-23 14:34:17 +0100619 strlcpy(has_slot_reply[count], "yes", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530620 count++;
621 }
622 }
623 else
624 {
Mayank Groverd22a1f52017-06-20 11:07:33 +0530625 strlcpy(has_slot_pname[count], pname, MAX_GET_VAR_NAME_SIZE);
Luca Weiss5e78d652022-03-23 14:34:17 +0100626 strlcpy(has_slot_reply[count], "no", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530627 count++;
628 }
629
630 /* Avoid over population of array provided */
631 if (count >= array_size)
632 {
633 dprintf(CRITICAL, "ERROR: Not able to parse all partitions\n");
634 return count;
635 }
636 }
637#ifdef AB_DEBUG
638 for (i=0; i<count; i++)
639 dprintf(INFO, "has-slot:%s:%s\n", has_slot_pname[i], has_slot_reply[i]);
640#endif
641 return count;
642}
643
644/*
645 Function to populate the slot meta used
646 for fastboot get var info publication.
647*/
648void partition_fill_slot_meta(struct ab_slot_info *slot_info)
649{
650 int i, current_slot_index;
651 struct partition_entry *ptn_entries = partition_get_partition_entries();
652 char buff[3];
653
654 /* Update slot info */
655 for(i=0; i<AB_SUPPORTED_SLOTS; i++)
656 {
657 current_slot_index = boot_slot_index[i];
Mayank Groverd22a1f52017-06-20 11:07:33 +0530658 strlcpy(slot_info[i].slot_is_unbootable_rsp,
659 slot_is_bootable(ptn_entries, current_slot_index)?"No":"Yes",
660 MAX_RSP_SIZE);
661 strlcpy(slot_info[i].slot_is_active_rsp,
662 slot_is_active(ptn_entries, current_slot_index)?"Yes":"No",
663 MAX_RSP_SIZE);
664 strlcpy(slot_info[i].slot_is_succesful_rsp,
665 slot_is_sucessful(ptn_entries, current_slot_index)?"Yes":"No",
666 MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530667 itoa(slot_retry_count(ptn_entries, current_slot_index),
668 (unsigned char *)buff, 2, 10);
Mayank Groverd22a1f52017-06-20 11:07:33 +0530669 strlcpy(slot_info[i].slot_retry_count_rsp, buff, MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530670 }
671}
672
673/*
674 Function to read and update the attributes of
675 GPT
676*/
677static int
678update_gpt(uint64_t gpt_start_addr,
679 uint64_t gpt_hdr_offset,
680 uint64_t gpt_entries_offset)
681{
682 char *buffer = NULL;
683 char *gpt_entries_ptr, *gpt_hdr_ptr, *tmp = NULL;
684 struct partition_entry *partition_entries = partition_get_partition_entries();
685 uint32_t partition_count = partition_get_partition_count();
686 unsigned i,max_partition_count = 0;
687 unsigned partition_entry_size = 0;
688 uint32_t block_size = mmc_get_device_blocksize();
689 uint32_t crc_val = 0;
690 int ret = 0;
691 uint64_t max_gpt_size_bytes =
692 (PARTITION_ENTRY_SIZE*NUM_PARTITIONS + GPT_HEADER_BLOCKS*block_size);
Mayank Grover9c866202017-06-29 17:48:55 +0530693 int lun = -1;
694
695 /* Get Current LUN for UFS target */
696 if (!platform_boot_dev_isemmc())
697 lun = mmc_get_lun();
Mayank Grovered699202017-05-30 20:04:10 +0530698
699 buffer = memalign(CACHE_LINE, ROUNDUP(max_gpt_size_bytes, CACHE_LINE));
Mayank Groverd22a1f52017-06-20 11:07:33 +0530700 if (!buffer)
701 {
702 dprintf(CRITICAL, "update_gpt: Failed at memory allocation\n");
703 goto out;
704 }
705
Mayank Grovered699202017-05-30 20:04:10 +0530706 ret = mmc_read(gpt_start_addr, (uint32_t *)buffer,
707 max_gpt_size_bytes);
708 if (ret)
709 {
710 dprintf(CRITICAL, "Failed to read GPT\n");
711 goto out;
712 }
713
714 /* 0. Intialise ptrs for header and entries */
715 gpt_entries_ptr = buffer + gpt_entries_offset*block_size;
716 gpt_hdr_ptr = buffer + gpt_hdr_offset*block_size;
717
718 /* 1. Update attributes_flag of partition entry */
719 tmp = gpt_entries_ptr;
720 for (i=0;i<partition_count;i++)
721 {
Mayank Grover9c866202017-06-29 17:48:55 +0530722 if (lun != -1)
723 {
724 /* Partition table is populated with entries from lun 0 to max lun.
725 * break out of the loop once we see the partition lun is > current lun */
726 if (partition_entries[i].lun > lun)
727 break;
728 /* Find the entry where the partition table for 'lun' starts
729 and then update the attributes */
730 if (partition_entries[i].lun != lun)
731 continue;
732 }
733
Mayank Grovered699202017-05-30 20:04:10 +0530734 /* Update the partition attributes */
735 PUT_LONG_LONG(&tmp[ATTRIBUTE_FLAG_OFFSET],
736 partition_entries[i].attribute_flag);
737 memscpy(tmp, PARTITION_TYPE_GUID_SIZE, partition_entries[i].type_guid,
738 PARTITION_TYPE_GUID_SIZE);
739
740 /* point to the next partition entry */
741 tmp += PARTITION_ENTRY_SIZE;
742 }
743
744 /* Calculate and update CRC of partition entries array */
745 max_partition_count =
746 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PARTITION_COUNT_OFFSET]);
747 partition_entry_size =
748 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PENTRY_SIZE_OFFSET]);
Kishor PK252e22c2017-08-30 17:26:43 +0530749
750 /* Check for partition entry size */
751 if (partition_entry_size != PARTITION_ENTRY_SIZE) {
752 dprintf(CRITICAL,"Invalid parition entry size\n");
753 goto out;
754 }
755
756 /* Check for maximum partition size */
757 if ((max_partition_count) > (MIN_PARTITION_ARRAY_SIZE /(partition_entry_size))) {
758 dprintf(CRITICAL, "Invalid maximum partition count\n");
759 goto out;
760 }
761
Mayank Grovered699202017-05-30 20:04:10 +0530762 crc_val = crc32(~0L, gpt_entries_ptr, ((max_partition_count) *
763 (partition_entry_size))) ^ (~0L);
764 PUT_LONG(&gpt_hdr_ptr[PARTITION_CRC_OFFSET], crc_val);
765
766
767 /* Write CRC to 0 before we calculate the crc of the GPT header */
768 crc_val = 0;
769 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
770 crc_val = crc32(~0L,gpt_hdr_ptr, GPT_HEADER_SIZE) ^ (~0L);
771 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
772
773 /* write to mmc */
774 ret = mmc_write(gpt_start_addr, max_gpt_size_bytes, buffer);
775 if (ret)
776 {
777 dprintf(CRITICAL, "Failed to write gpt\n");
778 goto out;
779 }
780out:
Mayank Groverd22a1f52017-06-20 11:07:33 +0530781 if (buffer)
782 free(buffer);
Mayank Grovered699202017-05-30 20:04:10 +0530783 return ret;
784}
785
786/**
787 Function to update the backup and primary gpt
788 partition.
789**/
790static void attributes_update()
791{
792 uint64_t offset;
793 uint64_t gpt_entries_offset, gpt_hdr_offset;
794 uint64_t gpt_start_addr;
795 int ret;
796 uint32_t block_size = mmc_get_device_blocksize();
797 unsigned max_entries_size_bytes = PARTITION_ENTRY_SIZE*NUM_PARTITIONS;
798 unsigned max_entries_blocks = max_entries_size_bytes/block_size;
799 unsigned max_gpt_blocks = GPT_HEADER_BLOCKS + max_entries_blocks;
Mayank Grover9c866202017-06-29 17:48:55 +0530800 int max_luns = 0, lun;
801 int cur_lun = mmc_get_lun();
Mayank Grovered699202017-05-30 20:04:10 +0530802
Mayank Grover9c866202017-06-29 17:48:55 +0530803#if defined(MMC_SDHCI_SUPPORT) || defined(UFS_SUPPORT)
804 if (platform_boot_dev_isemmc())
805 max_luns = 1;
806 else
807 max_luns = ufs_get_num_of_luns((struct ufs_dev*)target_mmc_device());
808#endif
809 for (lun = 0; lun < max_luns; lun++)
Mayank Grovered699202017-05-30 20:04:10 +0530810 {
Mayank Grover9c866202017-06-29 17:48:55 +0530811 /* Set current LUN */
812 mmc_set_lun(lun);
Mayank Grovered699202017-05-30 20:04:10 +0530813
Mayank Grover9c866202017-06-29 17:48:55 +0530814 /* Update Primary GPT */
815 offset = 0x01; /* offset is 0x1 for primary GPT */
816 gpt_start_addr = offset*block_size;
817 /* Take gpt_start_addr as start and calculate offset from that in block sz*/
818 gpt_hdr_offset = 0; /* For primary partition offset is zero */
819 gpt_entries_offset = GPT_HEADER_BLOCKS;
Mayank Grovered699202017-05-30 20:04:10 +0530820
Mayank Grover9c866202017-06-29 17:48:55 +0530821 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
822 if (ret)
823 {
824 dprintf(CRITICAL, "Failed to update Primary GPT\n");
825 return;
826 }
827
828 /* Update Secondary GPT */
829 offset = ((mmc_get_device_capacity()/block_size) - max_gpt_blocks);
830 gpt_start_addr = offset*block_size;
831 gpt_hdr_offset = max_entries_blocks;
832 gpt_entries_offset = 0; /* For secondary GPT entries offset is zero */
833
834 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
835 if (ret)
836 {
837 dprintf(CRITICAL, "Failed to update Secondary GPT\n");
838 return;
839 }
Mayank Grovered699202017-05-30 20:04:10 +0530840 }
Mayank Grover9c866202017-06-29 17:48:55 +0530841 mmc_set_lun(cur_lun);
Mayank Grovered699202017-05-30 20:04:10 +0530842 return;
843}