blob: 53a671ccd98acc508db3e4109f984fd15d98b8ce [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];
363 if (slot_is_bootable(ptn_entry, slt_index))
364 return i;
365 }
366
Mayank Groverbd8fdaa2018-01-25 13:04:54 +0530367 dprintf(CRITICAL, "ERROR: Unable to find any bootable slot");
368 return INVALID;
Mayank Grovered699202017-05-30 20:04:10 +0530369}
370
371int partition_find_boot_slot()
372{
Mayank Groverbd8fdaa2018-01-25 13:04:54 +0530373 int boot_slot, next_slot;
Mayank Grovered699202017-05-30 20:04:10 +0530374 int slt_index;
375 uint64_t boot_retry_count;
376 struct partition_entry *partition_entries = partition_get_partition_entries();
377
378 boot_retry_count = 0;
379 boot_slot = partition_find_active_slot();
380
381 if (boot_slot == INVALID)
382 goto out;
383
384 slt_index = boot_slot_index[boot_slot];
385
386 /* Boot if partition flag is set to sucessful */
387 if (partition_entries[slt_index].attribute_flag & PART_ATT_SUCCESSFUL_VAL)
388 goto out;
389
390 boot_retry_count = slot_retry_count(partition_entries, slt_index);
391
392#ifdef AB_DEBUG
393 dprintf(INFO, "Boot Partition:RetryCount %s:%lld\n", partition_entries[slt_index].name,
394 boot_retry_count);
395#endif
396 if (!boot_retry_count)
397 {
Mayank Groverc2ccc682017-10-24 19:02:49 +0530398 /* Mark slot invalid and unbootable */
399 partition_deactivate_slot(boot_slot);
Mayank Grovered699202017-05-30 20:04:10 +0530400
Mayank Groverbd8fdaa2018-01-25 13:04:54 +0530401 next_slot = next_active_bootable_slot(partition_entries);
402 if (next_slot != INVALID)
403 {
lijuang165fcbb2019-07-05 17:50:06 +0800404 partition_switch_slots(boot_slot, next_slot, false);
Mayank Groverbd8fdaa2018-01-25 13:04:54 +0530405 reboot_device(0);
406 }
407 else
408 {
409 boot_slot = INVALID;
410 }
Mayank Grovered699202017-05-30 20:04:10 +0530411 }
412 else
413 {
414 /* Do normal boot */
415 /* Decrement retry count */
416 partition_entries[slt_index].attribute_flag =
417 (partition_entries[slt_index].attribute_flag
418 & ~PART_ATT_MAX_RETRY_COUNT_VAL)
419 | ((boot_retry_count-1) << PART_ATT_MAX_RETRY_CNT_BIT);
420
421 if (!attributes_updated)
422 attributes_updated = true;
423
424 goto out;
425 }
426
427out:
428#ifdef AB_DEBUG
429 dprintf(INFO, "Booting SLOT %d\n", boot_slot);
430#endif
431 return boot_slot;
432}
433
434static
435void guid_update(struct partition_entry *partition_entries,
436 unsigned old_index,
437 unsigned new_index)
438{
439 unsigned char tmp_guid[PARTITION_TYPE_GUID_SIZE];
440
Mayank Groverff4587e2017-09-25 17:42:09 +0530441#ifdef AB_DEBUG
442 dprintf(INFO, "Swapping GUID (%s) --> (%s) \n",
443 partition_entries[old_index].name,
444 partition_entries[new_index].name);
445#endif
Mayank Grovered699202017-05-30 20:04:10 +0530446 memcpy(tmp_guid, partition_entries[old_index].type_guid,
447 PARTITION_TYPE_GUID_SIZE);
448 memcpy(partition_entries[old_index].type_guid,
449 partition_entries[new_index].type_guid,
450 PARTITION_TYPE_GUID_SIZE);
451 memcpy(partition_entries[new_index].type_guid, tmp_guid,
452 PARTITION_TYPE_GUID_SIZE);
453 return;
454}
455
456/*
457 Function to swap guids of slots
458*/
459static void
460swap_guid(int old_slot, int new_slot)
461{
462 unsigned i, j, tmp_strlen;
463 unsigned partition_cnt = partition_get_partition_count();
464 struct partition_entry *partition_entries =
465 partition_get_partition_entries();
466 const char *ptr_pname, *ptr_suffix;
467
468 if ( old_slot == new_slot)
469 return;
470
471 for(i = 0; i < partition_cnt; i++)
472 {
473 ptr_pname = (const char *)partition_entries[i].name;
474
475 /* Search for suffix in partition name */
476 if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(new_slot))))
477 {
478 for (j = i+1; j < partition_cnt; j++)
479 {
480 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(new_slot));
481 if (!strncmp((const char*)partition_entries[j].name, ptr_pname, tmp_strlen) &&
482 strstr((const char*)partition_entries[j].name, SUFFIX_SLOT(old_slot)))
483 guid_update(partition_entries, j, i);
484 }
485 }
486 else if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(old_slot))))
487 {
488 for (j = i+1; j < partition_cnt; j++)
489 {
490 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(old_slot));
491 if (!strncmp((const char *)partition_entries[j].name, ptr_pname, tmp_strlen) &&
492 strstr((const char *)partition_entries[j].name, SUFFIX_SLOT(new_slot)))
493 guid_update(partition_entries, i, j);
494 }
495 }
496 }
497}
498
499/*
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530500Function: To set active bit of all partitions of actve slot.
501 also, unset active bits of all other slot
502*/
503static void
504mark_all_partitions_active(signed slot)
505{
506 int i,j;
507 char *pname = NULL;
508 char *suffix_str = NULL;
509 struct partition_entry *partition_entries =
510 partition_get_partition_entries();
511 int partition_count = partition_get_partition_count();
512
513 for (i=0; i<partition_count; i++)
514 {
515 pname = (char *)partition_entries[i].name;
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530516#ifdef AB_DEBUG
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530517 dprintf(INFO, "Transversing partition %s\n", pname);
Mayank Grover0a20b6a2017-10-11 17:59:17 +0530518#endif
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530519 /* 1. Find partition, if it is A/B enabled. */
520 for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
521 {
522 suffix_str = strstr(pname, SUFFIX_SLOT(j));
523 if (suffix_str)
524 break;
525 }
526
527 if (suffix_str)
528 {
529 if (!strcmp(suffix_str, SUFFIX_SLOT(slot)))
530 /* 2a. Mark matching partition as active. */
531 partition_entries[i].attribute_flag |= PART_ATT_ACTIVE_VAL;
532 else
533 /* 2b. Unset active bit for all other partitions. */
534 partition_entries[i].attribute_flag &= ~PART_ATT_ACTIVE_VAL;
535 }
536 }
537 attributes_updated = true;
538}
539
540/*
Mayank Grovered699202017-05-30 20:04:10 +0530541 Function: Mark the slot to be active and also conditionally
542 update the slot parameters if there is a change.
543*/
544void partition_mark_active_slot(signed slot)
545{
546 if (active_slot == slot)
547 goto out;
548
Mayank Groverff4587e2017-09-25 17:42:09 +0530549 if(slot != INVALID)
Mayank Grovered699202017-05-30 20:04:10 +0530550 {
Mayank Groverff4587e2017-09-25 17:42:09 +0530551 dprintf(INFO, "Marking (%s) as active\n", SUFFIX_SLOT(slot));
552
553 /* 1. Swap GUID's to new slot */
554 swap_guid(active_slot, slot);
555
556 /* 2. Set Active bit for all partitions of active slot */
557 mark_all_partitions_active(slot);
Mayank Grovered699202017-05-30 20:04:10 +0530558 }
Mayank Groverff4587e2017-09-25 17:42:09 +0530559
Mayank Grovered699202017-05-30 20:04:10 +0530560 active_slot = slot;
561out:
562 if (attributes_updated)
563 attributes_update();
Mayank Grover25e3e3a2017-08-24 15:11:58 +0530564
Mayank Grovered699202017-05-30 20:04:10 +0530565 return;
566}
567
568/* Function to find if multislot is supported */
569bool partition_multislot_is_supported()
570{
571 return multislot_support;
572}
573
574/*
575 Function to populate partition meta used
576 for fastboot get var info publication.
577
578 Input partition_entries, partition_count and
579 buffer to fill information.
580
581*/
582int partition_fill_partition_meta(char has_slot_pname[][MAX_GET_VAR_NAME_SIZE],
583 char has_slot_reply[][MAX_RSP_SIZE],
584 int array_size)
585{
586 int i,j,tmp;
587 int count = 0;
588 char *pname = NULL;
589 int pname_size;
590 struct partition_entry *partition_entries =
591 partition_get_partition_entries();
592 int partition_count = partition_get_partition_count();
593 char *suffix_str;
594
595 for (i=0; i<partition_count; i++)
596 {
597 pname = (char *)partition_entries[i].name;
598 pname_size = strlen(pname);
599 suffix_str = NULL;
600 #ifdef AB_DEBUG
601 dprintf(INFO, "Transversing partition %s\n", pname);
602 #endif
603 /* 1. Find partition, if it is A/B enabled. */
604 for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
605 {
606 suffix_str = strstr(pname, SUFFIX_SLOT(j));
607 if (suffix_str)
608 break;
609 }
610
611 if (suffix_str)
612 {
613 if (!strcmp(suffix_str, SUFFIX_SLOT(SLOT_A)))
614 {
615 /* 2. put the partition name in array */
616 tmp = pname_size-strlen(suffix_str);
617 strlcpy(has_slot_pname[count], pname, tmp+1);
Mayank Groverd22a1f52017-06-20 11:07:33 +0530618 strlcpy(has_slot_reply[count], " Yes", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530619 count++;
620 }
621 }
622 else
623 {
Mayank Groverd22a1f52017-06-20 11:07:33 +0530624 strlcpy(has_slot_pname[count], pname, MAX_GET_VAR_NAME_SIZE);
625 strlcpy(has_slot_reply[count], " No", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530626 count++;
627 }
628
629 /* Avoid over population of array provided */
630 if (count >= array_size)
631 {
632 dprintf(CRITICAL, "ERROR: Not able to parse all partitions\n");
633 return count;
634 }
635 }
636#ifdef AB_DEBUG
637 for (i=0; i<count; i++)
638 dprintf(INFO, "has-slot:%s:%s\n", has_slot_pname[i], has_slot_reply[i]);
639#endif
640 return count;
641}
642
643/*
644 Function to populate the slot meta used
645 for fastboot get var info publication.
646*/
647void partition_fill_slot_meta(struct ab_slot_info *slot_info)
648{
649 int i, current_slot_index;
650 struct partition_entry *ptn_entries = partition_get_partition_entries();
651 char buff[3];
652
653 /* Update slot info */
654 for(i=0; i<AB_SUPPORTED_SLOTS; i++)
655 {
656 current_slot_index = boot_slot_index[i];
Mayank Groverd22a1f52017-06-20 11:07:33 +0530657 strlcpy(slot_info[i].slot_is_unbootable_rsp,
658 slot_is_bootable(ptn_entries, current_slot_index)?"No":"Yes",
659 MAX_RSP_SIZE);
660 strlcpy(slot_info[i].slot_is_active_rsp,
661 slot_is_active(ptn_entries, current_slot_index)?"Yes":"No",
662 MAX_RSP_SIZE);
663 strlcpy(slot_info[i].slot_is_succesful_rsp,
664 slot_is_sucessful(ptn_entries, current_slot_index)?"Yes":"No",
665 MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530666 itoa(slot_retry_count(ptn_entries, current_slot_index),
667 (unsigned char *)buff, 2, 10);
Mayank Groverd22a1f52017-06-20 11:07:33 +0530668 strlcpy(slot_info[i].slot_retry_count_rsp, buff, MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530669 }
670}
671
672/*
673 Function to read and update the attributes of
674 GPT
675*/
676static int
677update_gpt(uint64_t gpt_start_addr,
678 uint64_t gpt_hdr_offset,
679 uint64_t gpt_entries_offset)
680{
681 char *buffer = NULL;
682 char *gpt_entries_ptr, *gpt_hdr_ptr, *tmp = NULL;
683 struct partition_entry *partition_entries = partition_get_partition_entries();
684 uint32_t partition_count = partition_get_partition_count();
685 unsigned i,max_partition_count = 0;
686 unsigned partition_entry_size = 0;
687 uint32_t block_size = mmc_get_device_blocksize();
688 uint32_t crc_val = 0;
689 int ret = 0;
690 uint64_t max_gpt_size_bytes =
691 (PARTITION_ENTRY_SIZE*NUM_PARTITIONS + GPT_HEADER_BLOCKS*block_size);
Mayank Grover9c866202017-06-29 17:48:55 +0530692 int lun = -1;
693
694 /* Get Current LUN for UFS target */
695 if (!platform_boot_dev_isemmc())
696 lun = mmc_get_lun();
Mayank Grovered699202017-05-30 20:04:10 +0530697
698 buffer = memalign(CACHE_LINE, ROUNDUP(max_gpt_size_bytes, CACHE_LINE));
Mayank Groverd22a1f52017-06-20 11:07:33 +0530699 if (!buffer)
700 {
701 dprintf(CRITICAL, "update_gpt: Failed at memory allocation\n");
702 goto out;
703 }
704
Mayank Grovered699202017-05-30 20:04:10 +0530705 ret = mmc_read(gpt_start_addr, (uint32_t *)buffer,
706 max_gpt_size_bytes);
707 if (ret)
708 {
709 dprintf(CRITICAL, "Failed to read GPT\n");
710 goto out;
711 }
712
713 /* 0. Intialise ptrs for header and entries */
714 gpt_entries_ptr = buffer + gpt_entries_offset*block_size;
715 gpt_hdr_ptr = buffer + gpt_hdr_offset*block_size;
716
717 /* 1. Update attributes_flag of partition entry */
718 tmp = gpt_entries_ptr;
719 for (i=0;i<partition_count;i++)
720 {
Mayank Grover9c866202017-06-29 17:48:55 +0530721 if (lun != -1)
722 {
723 /* Partition table is populated with entries from lun 0 to max lun.
724 * break out of the loop once we see the partition lun is > current lun */
725 if (partition_entries[i].lun > lun)
726 break;
727 /* Find the entry where the partition table for 'lun' starts
728 and then update the attributes */
729 if (partition_entries[i].lun != lun)
730 continue;
731 }
732
Mayank Grovered699202017-05-30 20:04:10 +0530733 /* Update the partition attributes */
734 PUT_LONG_LONG(&tmp[ATTRIBUTE_FLAG_OFFSET],
735 partition_entries[i].attribute_flag);
736 memscpy(tmp, PARTITION_TYPE_GUID_SIZE, partition_entries[i].type_guid,
737 PARTITION_TYPE_GUID_SIZE);
738
739 /* point to the next partition entry */
740 tmp += PARTITION_ENTRY_SIZE;
741 }
742
743 /* Calculate and update CRC of partition entries array */
744 max_partition_count =
745 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PARTITION_COUNT_OFFSET]);
746 partition_entry_size =
747 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PENTRY_SIZE_OFFSET]);
Kishor PK252e22c2017-08-30 17:26:43 +0530748
749 /* Check for partition entry size */
750 if (partition_entry_size != PARTITION_ENTRY_SIZE) {
751 dprintf(CRITICAL,"Invalid parition entry size\n");
752 goto out;
753 }
754
755 /* Check for maximum partition size */
756 if ((max_partition_count) > (MIN_PARTITION_ARRAY_SIZE /(partition_entry_size))) {
757 dprintf(CRITICAL, "Invalid maximum partition count\n");
758 goto out;
759 }
760
Mayank Grovered699202017-05-30 20:04:10 +0530761 crc_val = crc32(~0L, gpt_entries_ptr, ((max_partition_count) *
762 (partition_entry_size))) ^ (~0L);
763 PUT_LONG(&gpt_hdr_ptr[PARTITION_CRC_OFFSET], crc_val);
764
765
766 /* Write CRC to 0 before we calculate the crc of the GPT header */
767 crc_val = 0;
768 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
769 crc_val = crc32(~0L,gpt_hdr_ptr, GPT_HEADER_SIZE) ^ (~0L);
770 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
771
772 /* write to mmc */
773 ret = mmc_write(gpt_start_addr, max_gpt_size_bytes, buffer);
774 if (ret)
775 {
776 dprintf(CRITICAL, "Failed to write gpt\n");
777 goto out;
778 }
779out:
Mayank Groverd22a1f52017-06-20 11:07:33 +0530780 if (buffer)
781 free(buffer);
Mayank Grovered699202017-05-30 20:04:10 +0530782 return ret;
783}
784
785/**
786 Function to update the backup and primary gpt
787 partition.
788**/
789static void attributes_update()
790{
791 uint64_t offset;
792 uint64_t gpt_entries_offset, gpt_hdr_offset;
793 uint64_t gpt_start_addr;
794 int ret;
795 uint32_t block_size = mmc_get_device_blocksize();
796 unsigned max_entries_size_bytes = PARTITION_ENTRY_SIZE*NUM_PARTITIONS;
797 unsigned max_entries_blocks = max_entries_size_bytes/block_size;
798 unsigned max_gpt_blocks = GPT_HEADER_BLOCKS + max_entries_blocks;
Mayank Grover9c866202017-06-29 17:48:55 +0530799 int max_luns = 0, lun;
800 int cur_lun = mmc_get_lun();
Mayank Grovered699202017-05-30 20:04:10 +0530801
Mayank Grover9c866202017-06-29 17:48:55 +0530802#if defined(MMC_SDHCI_SUPPORT) || defined(UFS_SUPPORT)
803 if (platform_boot_dev_isemmc())
804 max_luns = 1;
805 else
806 max_luns = ufs_get_num_of_luns((struct ufs_dev*)target_mmc_device());
807#endif
808 for (lun = 0; lun < max_luns; lun++)
Mayank Grovered699202017-05-30 20:04:10 +0530809 {
Mayank Grover9c866202017-06-29 17:48:55 +0530810 /* Set current LUN */
811 mmc_set_lun(lun);
Mayank Grovered699202017-05-30 20:04:10 +0530812
Mayank Grover9c866202017-06-29 17:48:55 +0530813 /* Update Primary GPT */
814 offset = 0x01; /* offset is 0x1 for primary GPT */
815 gpt_start_addr = offset*block_size;
816 /* Take gpt_start_addr as start and calculate offset from that in block sz*/
817 gpt_hdr_offset = 0; /* For primary partition offset is zero */
818 gpt_entries_offset = GPT_HEADER_BLOCKS;
Mayank Grovered699202017-05-30 20:04:10 +0530819
Mayank Grover9c866202017-06-29 17:48:55 +0530820 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
821 if (ret)
822 {
823 dprintf(CRITICAL, "Failed to update Primary GPT\n");
824 return;
825 }
826
827 /* Update Secondary GPT */
828 offset = ((mmc_get_device_capacity()/block_size) - max_gpt_blocks);
829 gpt_start_addr = offset*block_size;
830 gpt_hdr_offset = max_entries_blocks;
831 gpt_entries_offset = 0; /* For secondary GPT entries offset is zero */
832
833 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
834 if (ret)
835 {
836 dprintf(CRITICAL, "Failed to update Secondary GPT\n");
837 return;
838 }
Mayank Grovered699202017-05-30 20:04:10 +0530839 }
Mayank Grover9c866202017-06-29 17:48:55 +0530840 mmc_set_lun(cur_lun);
Mayank Grovered699202017-05-30 20:04:10 +0530841 return;
842}