blob: bd900d9e0f3b8916bac04a84badd7b37b91c5c74 [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>
34
35//#define AB_DEBUG
36
37/* Slot suffix */
38const char *suffix_slot[] = {"_a",
39 "_b"};
40
41/* local global variables */
42static signed active_slot = INVALID; /* to store current active slot */
43static bool attributes_updated = false; /* to store if we need to update partition table */
44static bool multislot_support = false; /* to store if multislot support is present */
45
46static int boot_slot_index[AB_SUPPORTED_SLOTS]; /* store index for boot parition */
47
48/* local functions. */
49static void attributes_update();
50
51/*
52 Function: To read slot attribute of
53 of the partition_entry
54*/
55inline bool slot_is_active(struct partition_entry *partition_entries,
56 unsigned index)
57{
58 if ((partition_entries[index].attribute_flag &
59 PART_ATT_ACTIVE_VAL)>>PART_ATT_ACTIVE_BIT)
60 return true;
61 else
62 return false;
63}
64
65inline bool slot_is_sucessful(struct partition_entry *partition_entries,
66 unsigned index)
67{
68 if ((partition_entries[index].attribute_flag &
69 PART_ATT_SUCCESSFUL_VAL)>>PART_ATT_SUCCESS_BIT)
70 return true;
71 else
72 return false;
73}
74
75inline unsigned slot_retry_count(struct partition_entry *partition_entries,
76 unsigned index)
77{
78 return ((partition_entries[index].attribute_flag
79 & PART_ATT_MAX_RETRY_COUNT_VAL) >> PART_ATT_MAX_RETRY_CNT_BIT);
80}
81
82inline unsigned slot_priority(struct partition_entry *partition_entries,
83 unsigned index)
84{
85 return ((partition_entries[index].attribute_flag
86 & PART_ATT_PRIORITY_VAL)>>PART_ATT_PRIORITY_BIT);
87}
88
89inline bool slot_is_bootable(struct partition_entry *partition_entries,
90 unsigned index)
91{
92 if ((partition_entries[index].attribute_flag &
93 PART_ATT_UNBOOTABLE_VAL)>>PART_ATT_UNBOOTABLE_BIT)
94 return false;
95 else
96 return true;
97}
98
99/*
100 Function scan boot partition to find SLOT_A/SLOT_B suffix.
101 If found than make multislot_boot flag true and
102 scans another partition.
103*/
104bool partition_scan_for_multislot()
105{
106 int i, j, count = 0;
107 char *pname = NULL;
108 int strlen_boot = strlen("boot");
109 int partition_count = partition_get_partition_count();
110 struct partition_entry *partition_entries =
111 partition_get_partition_entries();
112
113 multislot_support = false;
114
115 if (partition_count > NUM_PARTITIONS)
116 {
117 dprintf(CRITICAL, "ERROR: partition_count more than supported.\n");
118 return multislot_support;
119 }
120
121 for (i = 0; i < partition_count; i++)
122 {
123 pname = (char *)partition_entries[i].name;
124#ifdef AB_DEBUG
125 dprintf(INFO, "Transversing partition %s\n", pname);
126#endif
127 if (!strncmp((const char *)partition_entries[i].name, "boot", strlen_boot))
128 {
129 pname += strlen_boot;
130 if (*pname)
131 {
132#ifdef AB_DEBUG
133 dprintf(INFO, "Suffix: %s\n", pname);
134#endif
135 for (j =0; j<AB_SUPPORTED_SLOTS; j++)
136 {
137 if (!strcmp(pname, suffix_slot[j]))
138 {
139 /* cache these variables as they are used multiple times */
140 boot_slot_index[j] = i;
141 if (!multislot_support)
142 multislot_support =true;
143 count ++;
144 }
145 }
146 /* Break out of loop if all slot index are found*/
147 if (count == AB_SUPPORTED_SLOTS)
148 break;
149 }
150 else
151 {
152#ifdef AB_DEBUG
153 dprintf(INFO, "Partition Table is not a/b supported\n");
154#endif
155 break;
156 }
157 }
158 }
159 return multislot_support;
160}
161
162/*
163 Function: To reset partition attributes
164 This function reset partition_priority, retry_count
165 and clear successful and bootable bits.
166*/
167void partition_reset_attributes(unsigned index)
168{
169 struct partition_entry *partition_entries =
170 partition_get_partition_entries();
171
172 partition_entries[index].attribute_flag |= (PART_ATT_PRIORITY_VAL |
173 PART_ATT_MAX_RETRY_COUNT_VAL);
174
175 partition_entries[index].attribute_flag &= ((~PART_ATT_SUCCESSFUL_VAL) &
176 (~PART_ATT_UNBOOTABLE_VAL));
177
178 if (!attributes_updated)
179 attributes_updated = true;
180
181 /* Make attributes persistant */
182 partition_mark_active_slot(active_slot);
183}
184
185/*
186 Function: Switch active partitions.
187*/
188void partition_switch_slots(int old_slot, int new_slot)
189{
190#ifdef AB_DEBUG
191 dprintf(INFO, "Switching slots %s to %s\n",
192 SUFFIX_SLOT(old_slot), SUFFIX_SLOT(new_slot));
193#endif
194 struct partition_entry *partition_entries =
195 partition_get_partition_entries();
196 int old_slot_index = boot_slot_index[old_slot];
197 int new_slot_index = boot_slot_index[new_slot];
198
199 /* Mark current slot inactive, keeping all other attributes intact */
200 partition_entries[old_slot_index].attribute_flag &= ~PART_ATT_ACTIVE_VAL;
201
202 /* Mark new slot active */
203 partition_entries[new_slot_index].attribute_flag |=
204 ((PART_ATT_PRIORITY_VAL |
205 PART_ATT_ACTIVE_VAL |
206 PART_ATT_MAX_RETRY_COUNT_VAL));
207 partition_entries[new_slot_index].attribute_flag &=
208 (~PART_ATT_SUCCESSFUL_VAL
209 & ~PART_ATT_UNBOOTABLE_VAL);
210
211 if (!attributes_updated)
212 attributes_updated = true;
213
214 /* Update active slot and gpt table */
215 partition_mark_active_slot(new_slot);
216 return;
217}
218
219/*
220 This function returns the most priority and active slot,
221 also you need to update the global state seperately.
222
223*/
224int partition_find_active_slot()
225{
226 unsigned current_priority;
227 int i, count = 0;
228 bool current_bootable_bit;
229 bool current_active_bit;
230 unsigned boot_priority;
231 struct partition_entry *partition_entries = partition_get_partition_entries();
232
233 /* Return current active slot if already found */
234 if (active_slot != INVALID)
235 return active_slot;
236
237 for (boot_priority = MAX_PRIORITY;
238 boot_priority > 0; boot_priority--)
239 {
240 /* Search valid boot slot with highest priority */
241 for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
242 {
243 current_priority = slot_priority(partition_entries, boot_slot_index[i]);
244 current_active_bit = slot_is_active(partition_entries, boot_slot_index[i]);
245 current_bootable_bit = slot_is_bootable(partition_entries, boot_slot_index[i]);
246
247 /* Count number of slots with all attributes as zero */
248 if ( !current_priority &&
249 !current_active_bit &&
250 current_bootable_bit)
251 {
252 count ++;
253 continue;
254 }
255
256#ifdef AB_DEBUG
257 dprintf(INFO, "Slot:Priority:Active:Bootable %s:%d:%d:%d \n",
258 partition_entries[boot_slot_index[i]].name,
259 current_priority,
260 current_active_bit,
261 current_bootable_bit);
262#endif
263 if (boot_priority == current_priority)
264 {
265 if (current_active_bit &&
266 current_bootable_bit)
267 {
268#ifdef AB_DEBUG
269 dprintf(INFO, "Slot (%s) is Valid High Priority Slot\n", SUFFIX_SLOT(i));
270#endif
271 return i;
272 }
273 }
274 }
275
276 /* All slots are zeroed, this is first bootup */
277 /* Marking and trying SLOT 0 as default */
278 if (count == AB_SUPPORTED_SLOTS)
279 {
280 /* Update the priority of the boot slot */
281 partition_entries[boot_slot_index[SLOT_A]].attribute_flag |=
282 ((PART_ATT_PRIORITY_VAL |
283 PART_ATT_ACTIVE_VAL |
284 PART_ATT_MAX_RETRY_COUNT_VAL) &
285 (~PART_ATT_SUCCESSFUL_VAL &
286 ~PART_ATT_UNBOOTABLE_VAL));
287 if (!attributes_updated)
288 attributes_updated = true;
289 return SLOT_A;
290 }
291 }
292 /* If no valid slot */
293 return INVALID;
294}
295
296static int
297next_active_bootable_slot(struct partition_entry *ptn_entry)
298{
299 int i, slt_index;
300 for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
301 {
302 slt_index = boot_slot_index[i];
303 if (slot_is_bootable(ptn_entry, slt_index))
304 return i;
305 }
306
307 /* NO Bootable slot */
308 panic("ERROR: Unable to find any bootable slot");
309 return 0;
310}
311
312int partition_find_boot_slot()
313{
314 int boot_slot;
315 int slt_index;
316 uint64_t boot_retry_count;
317 struct partition_entry *partition_entries = partition_get_partition_entries();
318
319 boot_retry_count = 0;
320 boot_slot = partition_find_active_slot();
321
322 if (boot_slot == INVALID)
323 goto out;
324
325 slt_index = boot_slot_index[boot_slot];
326
327 /* Boot if partition flag is set to sucessful */
328 if (partition_entries[slt_index].attribute_flag & PART_ATT_SUCCESSFUL_VAL)
329 goto out;
330
331 boot_retry_count = slot_retry_count(partition_entries, slt_index);
332
333#ifdef AB_DEBUG
334 dprintf(INFO, "Boot Partition:RetryCount %s:%lld\n", partition_entries[slt_index].name,
335 boot_retry_count);
336#endif
337 if (!boot_retry_count)
338 {
339 /* Mark slot invalide and unbootable */
340 partition_entries[slt_index].attribute_flag |=
341 (PART_ATT_UNBOOTABLE_VAL &
342 ~PART_ATT_ACTIVE_VAL &
343 ~PART_ATT_PRIORITY_VAL);
344
345 partition_switch_slots(boot_slot, next_active_bootable_slot(partition_entries));
346
347 reboot_device(0);
348 }
349 else
350 {
351 /* Do normal boot */
352 /* Decrement retry count */
353 partition_entries[slt_index].attribute_flag =
354 (partition_entries[slt_index].attribute_flag
355 & ~PART_ATT_MAX_RETRY_COUNT_VAL)
356 | ((boot_retry_count-1) << PART_ATT_MAX_RETRY_CNT_BIT);
357
358 if (!attributes_updated)
359 attributes_updated = true;
360
361 goto out;
362 }
363
364out:
365#ifdef AB_DEBUG
366 dprintf(INFO, "Booting SLOT %d\n", boot_slot);
367#endif
368 return boot_slot;
369}
370
371static
372void guid_update(struct partition_entry *partition_entries,
373 unsigned old_index,
374 unsigned new_index)
375{
376 unsigned char tmp_guid[PARTITION_TYPE_GUID_SIZE];
377
378 memcpy(tmp_guid, partition_entries[old_index].type_guid,
379 PARTITION_TYPE_GUID_SIZE);
380 memcpy(partition_entries[old_index].type_guid,
381 partition_entries[new_index].type_guid,
382 PARTITION_TYPE_GUID_SIZE);
383 memcpy(partition_entries[new_index].type_guid, tmp_guid,
384 PARTITION_TYPE_GUID_SIZE);
385 return;
386}
387
388/*
389 Function to swap guids of slots
390*/
391static void
392swap_guid(int old_slot, int new_slot)
393{
394 unsigned i, j, tmp_strlen;
395 unsigned partition_cnt = partition_get_partition_count();
396 struct partition_entry *partition_entries =
397 partition_get_partition_entries();
398 const char *ptr_pname, *ptr_suffix;
399
400 if ( old_slot == new_slot)
401 return;
402
403 for(i = 0; i < partition_cnt; i++)
404 {
405 ptr_pname = (const char *)partition_entries[i].name;
406
407 /* Search for suffix in partition name */
408 if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(new_slot))))
409 {
410 for (j = i+1; j < partition_cnt; j++)
411 {
412 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(new_slot));
413 if (!strncmp((const char*)partition_entries[j].name, ptr_pname, tmp_strlen) &&
414 strstr((const char*)partition_entries[j].name, SUFFIX_SLOT(old_slot)))
415 guid_update(partition_entries, j, i);
416 }
417 }
418 else if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(old_slot))))
419 {
420 for (j = i+1; j < partition_cnt; j++)
421 {
422 tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(old_slot));
423 if (!strncmp((const char *)partition_entries[j].name, ptr_pname, tmp_strlen) &&
424 strstr((const char *)partition_entries[j].name, SUFFIX_SLOT(new_slot)))
425 guid_update(partition_entries, i, j);
426 }
427 }
428 }
429}
430
431/*
432 Function: Mark the slot to be active and also conditionally
433 update the slot parameters if there is a change.
434*/
435void partition_mark_active_slot(signed slot)
436{
437 if (active_slot == slot)
438 goto out;
439
440 switch (active_slot)
441 {
442 case INVALID:
443 if (slot != SLOT_A)
444 swap_guid(SLOT_A, slot);
445 goto out;
446 default:
447 if (slot == INVALID)
448 swap_guid(active_slot, SLOT_A);
449 else
450 swap_guid(active_slot, slot);
451 }
452 active_slot = slot;
453out:
454 if (attributes_updated)
455 attributes_update();
456 return;
457}
458
459/* Function to find if multislot is supported */
460bool partition_multislot_is_supported()
461{
462 return multislot_support;
463}
464
465/*
466 Function to populate partition meta used
467 for fastboot get var info publication.
468
469 Input partition_entries, partition_count and
470 buffer to fill information.
471
472*/
473int partition_fill_partition_meta(char has_slot_pname[][MAX_GET_VAR_NAME_SIZE],
474 char has_slot_reply[][MAX_RSP_SIZE],
475 int array_size)
476{
477 int i,j,tmp;
478 int count = 0;
479 char *pname = NULL;
480 int pname_size;
481 struct partition_entry *partition_entries =
482 partition_get_partition_entries();
483 int partition_count = partition_get_partition_count();
484 char *suffix_str;
485
486 for (i=0; i<partition_count; i++)
487 {
488 pname = (char *)partition_entries[i].name;
489 pname_size = strlen(pname);
490 suffix_str = NULL;
491 #ifdef AB_DEBUG
492 dprintf(INFO, "Transversing partition %s\n", pname);
493 #endif
494 /* 1. Find partition, if it is A/B enabled. */
495 for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
496 {
497 suffix_str = strstr(pname, SUFFIX_SLOT(j));
498 if (suffix_str)
499 break;
500 }
501
502 if (suffix_str)
503 {
504 if (!strcmp(suffix_str, SUFFIX_SLOT(SLOT_A)))
505 {
506 /* 2. put the partition name in array */
507 tmp = pname_size-strlen(suffix_str);
508 strlcpy(has_slot_pname[count], pname, tmp+1);
Mayank Groverd22a1f52017-06-20 11:07:33 +0530509 strlcpy(has_slot_reply[count], " Yes", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530510 count++;
511 }
512 }
513 else
514 {
Mayank Groverd22a1f52017-06-20 11:07:33 +0530515 strlcpy(has_slot_pname[count], pname, MAX_GET_VAR_NAME_SIZE);
516 strlcpy(has_slot_reply[count], " No", MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530517 count++;
518 }
519
520 /* Avoid over population of array provided */
521 if (count >= array_size)
522 {
523 dprintf(CRITICAL, "ERROR: Not able to parse all partitions\n");
524 return count;
525 }
526 }
527#ifdef AB_DEBUG
528 for (i=0; i<count; i++)
529 dprintf(INFO, "has-slot:%s:%s\n", has_slot_pname[i], has_slot_reply[i]);
530#endif
531 return count;
532}
533
534/*
535 Function to populate the slot meta used
536 for fastboot get var info publication.
537*/
538void partition_fill_slot_meta(struct ab_slot_info *slot_info)
539{
540 int i, current_slot_index;
541 struct partition_entry *ptn_entries = partition_get_partition_entries();
542 char buff[3];
543
544 /* Update slot info */
545 for(i=0; i<AB_SUPPORTED_SLOTS; i++)
546 {
547 current_slot_index = boot_slot_index[i];
Mayank Groverd22a1f52017-06-20 11:07:33 +0530548 strlcpy(slot_info[i].slot_is_unbootable_rsp,
549 slot_is_bootable(ptn_entries, current_slot_index)?"No":"Yes",
550 MAX_RSP_SIZE);
551 strlcpy(slot_info[i].slot_is_active_rsp,
552 slot_is_active(ptn_entries, current_slot_index)?"Yes":"No",
553 MAX_RSP_SIZE);
554 strlcpy(slot_info[i].slot_is_succesful_rsp,
555 slot_is_sucessful(ptn_entries, current_slot_index)?"Yes":"No",
556 MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530557 itoa(slot_retry_count(ptn_entries, current_slot_index),
558 (unsigned char *)buff, 2, 10);
Mayank Groverd22a1f52017-06-20 11:07:33 +0530559 strlcpy(slot_info[i].slot_retry_count_rsp, buff, MAX_RSP_SIZE);
Mayank Grovered699202017-05-30 20:04:10 +0530560 }
561}
562
563/*
564 Function to read and update the attributes of
565 GPT
566*/
567static int
568update_gpt(uint64_t gpt_start_addr,
569 uint64_t gpt_hdr_offset,
570 uint64_t gpt_entries_offset)
571{
572 char *buffer = NULL;
573 char *gpt_entries_ptr, *gpt_hdr_ptr, *tmp = NULL;
574 struct partition_entry *partition_entries = partition_get_partition_entries();
575 uint32_t partition_count = partition_get_partition_count();
576 unsigned i,max_partition_count = 0;
577 unsigned partition_entry_size = 0;
578 uint32_t block_size = mmc_get_device_blocksize();
579 uint32_t crc_val = 0;
580 int ret = 0;
581 uint64_t max_gpt_size_bytes =
582 (PARTITION_ENTRY_SIZE*NUM_PARTITIONS + GPT_HEADER_BLOCKS*block_size);
583
584 buffer = memalign(CACHE_LINE, ROUNDUP(max_gpt_size_bytes, CACHE_LINE));
Mayank Groverd22a1f52017-06-20 11:07:33 +0530585 if (!buffer)
586 {
587 dprintf(CRITICAL, "update_gpt: Failed at memory allocation\n");
588 goto out;
589 }
590
Mayank Grovered699202017-05-30 20:04:10 +0530591 ret = mmc_read(gpt_start_addr, (uint32_t *)buffer,
592 max_gpt_size_bytes);
593 if (ret)
594 {
595 dprintf(CRITICAL, "Failed to read GPT\n");
596 goto out;
597 }
598
599 /* 0. Intialise ptrs for header and entries */
600 gpt_entries_ptr = buffer + gpt_entries_offset*block_size;
601 gpt_hdr_ptr = buffer + gpt_hdr_offset*block_size;
602
603 /* 1. Update attributes_flag of partition entry */
604 tmp = gpt_entries_ptr;
605 for (i=0;i<partition_count;i++)
606 {
607 /* Update the partition attributes */
608 PUT_LONG_LONG(&tmp[ATTRIBUTE_FLAG_OFFSET],
609 partition_entries[i].attribute_flag);
610 memscpy(tmp, PARTITION_TYPE_GUID_SIZE, partition_entries[i].type_guid,
611 PARTITION_TYPE_GUID_SIZE);
612
613 /* point to the next partition entry */
614 tmp += PARTITION_ENTRY_SIZE;
615 }
616
617 /* Calculate and update CRC of partition entries array */
618 max_partition_count =
619 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PARTITION_COUNT_OFFSET]);
620 partition_entry_size =
621 GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PENTRY_SIZE_OFFSET]);
622 crc_val = crc32(~0L, gpt_entries_ptr, ((max_partition_count) *
623 (partition_entry_size))) ^ (~0L);
624 PUT_LONG(&gpt_hdr_ptr[PARTITION_CRC_OFFSET], crc_val);
625
626
627 /* Write CRC to 0 before we calculate the crc of the GPT header */
628 crc_val = 0;
629 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
630 crc_val = crc32(~0L,gpt_hdr_ptr, GPT_HEADER_SIZE) ^ (~0L);
631 PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
632
633 /* write to mmc */
634 ret = mmc_write(gpt_start_addr, max_gpt_size_bytes, buffer);
635 if (ret)
636 {
637 dprintf(CRITICAL, "Failed to write gpt\n");
638 goto out;
639 }
640out:
Mayank Groverd22a1f52017-06-20 11:07:33 +0530641 if (buffer)
642 free(buffer);
Mayank Grovered699202017-05-30 20:04:10 +0530643 return ret;
644}
645
646/**
647 Function to update the backup and primary gpt
648 partition.
649**/
650static void attributes_update()
651{
652 uint64_t offset;
653 uint64_t gpt_entries_offset, gpt_hdr_offset;
654 uint64_t gpt_start_addr;
655 int ret;
656 uint32_t block_size = mmc_get_device_blocksize();
657 unsigned max_entries_size_bytes = PARTITION_ENTRY_SIZE*NUM_PARTITIONS;
658 unsigned max_entries_blocks = max_entries_size_bytes/block_size;
659 unsigned max_gpt_blocks = GPT_HEADER_BLOCKS + max_entries_blocks;
660
661 /* Update Primary GPT */
662 offset = 0x01; /* offset is 0x1 for primary GPT */
663 gpt_start_addr = offset*block_size;
664 /* Take gpt_start_addr as start and calculate offset from that in block sz*/
665 gpt_hdr_offset = 0; /* For primary partition offset is zero */
666 gpt_entries_offset = GPT_HEADER_BLOCKS;
667
668 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
669 if (ret)
670 {
671 dprintf(CRITICAL, "Failed to update Primary GPT\n");
672 return;
673 }
674
675 /* Update Secondary GPT */
676 offset = ((mmc_get_device_capacity()/block_size) - max_gpt_blocks);
677 gpt_start_addr = offset*block_size;
678 gpt_hdr_offset = max_entries_blocks;
679 gpt_entries_offset = 0; /* For secondary GPT entries offset is zero */
680
681 ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
682 if (ret)
683 {
684 dprintf(CRITICAL, "Failed to update Secondary GPT\n");
685 return;
686 }
687 return;
688}