Merge "platform: msm_shared: a/b support, add APIs to support a/b partitions."
diff --git a/platform/msm_shared/ab_partition_parser.c b/platform/msm_shared/ab_partition_parser.c
new file mode 100644
index 0000000..db37d00
--- /dev/null
+++ b/platform/msm_shared/ab_partition_parser.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of The Linux Foundation nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <crc32.h>
+#include <ab_partition_parser.h>
+#include <partition_parser.h>
+
+//#define AB_DEBUG
+
+/* Slot suffix */
+const char *suffix_slot[] = {"_a",
+		"_b"};
+
+/* local global variables */
+static signed active_slot = INVALID;		/* to store current active slot */
+static bool attributes_updated = false;		/* to store if we need to update partition table */
+static bool multislot_support = false;		/* to store if multislot support is present */
+
+static int boot_slot_index[AB_SUPPORTED_SLOTS];	/* store index for boot parition */
+
+/* local functions. */
+static void attributes_update();
+
+/*
+	Function: To read slot attribute of
+		of the partition_entry
+*/
+inline bool slot_is_active(struct partition_entry *partition_entries,
+					unsigned index)
+{
+	if ((partition_entries[index].attribute_flag &
+		PART_ATT_ACTIVE_VAL)>>PART_ATT_ACTIVE_BIT)
+		return true;
+	else
+		return false;
+}
+
+inline bool slot_is_sucessful(struct partition_entry *partition_entries,
+						unsigned index)
+{
+	if ((partition_entries[index].attribute_flag &
+		PART_ATT_SUCCESSFUL_VAL)>>PART_ATT_SUCCESS_BIT)
+		return true;
+	else
+		return false;
+}
+
+inline unsigned slot_retry_count(struct partition_entry *partition_entries,
+						unsigned index)
+{
+	return ((partition_entries[index].attribute_flag
+		& PART_ATT_MAX_RETRY_COUNT_VAL) >> PART_ATT_MAX_RETRY_CNT_BIT);
+}
+
+inline unsigned slot_priority(struct partition_entry *partition_entries,
+						unsigned index)
+{
+	return ((partition_entries[index].attribute_flag
+		& PART_ATT_PRIORITY_VAL)>>PART_ATT_PRIORITY_BIT);
+}
+
+inline bool slot_is_bootable(struct partition_entry *partition_entries,
+						unsigned index)
+{
+	if ((partition_entries[index].attribute_flag &
+		PART_ATT_UNBOOTABLE_VAL)>>PART_ATT_UNBOOTABLE_BIT)
+		return false;
+	else
+		return true;
+}
+
+/*
+	Function scan boot partition to find SLOT_A/SLOT_B suffix.
+	If found than make multislot_boot flag true and
+	scans another partition.
+*/
+bool partition_scan_for_multislot()
+{
+	int i, j, count = 0;
+	char *pname = NULL;
+	int strlen_boot = strlen("boot");
+	int partition_count = partition_get_partition_count();
+	struct partition_entry *partition_entries =
+				partition_get_partition_entries();
+
+	multislot_support = false;
+
+	if (partition_count > NUM_PARTITIONS)
+	{
+		dprintf(CRITICAL, "ERROR: partition_count more than supported.\n");
+		return multislot_support;
+	}
+
+	for (i = 0; i < partition_count; i++)
+	{
+		pname = (char *)partition_entries[i].name;
+#ifdef AB_DEBUG
+		dprintf(INFO, "Transversing partition %s\n", pname);
+#endif
+		if (!strncmp((const char *)partition_entries[i].name, "boot", strlen_boot))
+		{
+			pname += strlen_boot;
+			if (*pname)
+			{
+#ifdef AB_DEBUG
+		dprintf(INFO, "Suffix: %s\n", pname);
+#endif
+				for (j =0; j<AB_SUPPORTED_SLOTS; j++)
+				{
+					if (!strcmp(pname, suffix_slot[j]))
+					{
+						/* cache these variables as they are used multiple times */
+						boot_slot_index[j] = i;
+						if (!multislot_support)
+							multislot_support =true;
+						count ++;
+					}
+				}
+				/* Break out of loop if all slot index are found*/
+				if (count == AB_SUPPORTED_SLOTS)
+					break;
+			}
+			else
+			{
+#ifdef AB_DEBUG
+		dprintf(INFO, "Partition Table is not a/b supported\n");
+#endif
+				break;
+			}
+		}
+	}
+	return multislot_support;
+}
+
+/*
+	Function: To reset partition attributes
+	This function reset partition_priority, retry_count
+	and clear successful and bootable bits.
+*/
+void partition_reset_attributes(unsigned index)
+{
+	struct partition_entry *partition_entries =
+					partition_get_partition_entries();
+
+	partition_entries[index].attribute_flag |= (PART_ATT_PRIORITY_VAL |
+				PART_ATT_MAX_RETRY_COUNT_VAL);
+
+	partition_entries[index].attribute_flag &= ((~PART_ATT_SUCCESSFUL_VAL) &
+						(~PART_ATT_UNBOOTABLE_VAL));
+
+	if (!attributes_updated)
+		attributes_updated = true;
+
+	/* Make attributes persistant */
+	partition_mark_active_slot(active_slot);
+}
+
+/*
+	Function: Switch active partitions.
+*/
+void partition_switch_slots(int old_slot, int new_slot)
+{
+#ifdef AB_DEBUG
+	dprintf(INFO, "Switching slots %s to %s\n",
+				SUFFIX_SLOT(old_slot), SUFFIX_SLOT(new_slot));
+#endif
+	struct partition_entry *partition_entries =
+					partition_get_partition_entries();
+	int old_slot_index = boot_slot_index[old_slot];
+	int new_slot_index = boot_slot_index[new_slot];
+
+	/* Mark current slot inactive, keeping all other attributes intact */
+	partition_entries[old_slot_index].attribute_flag &= ~PART_ATT_ACTIVE_VAL;
+
+	/* Mark new slot active */
+	partition_entries[new_slot_index].attribute_flag |=
+						((PART_ATT_PRIORITY_VAL |
+						PART_ATT_ACTIVE_VAL |
+						PART_ATT_MAX_RETRY_COUNT_VAL));
+	partition_entries[new_slot_index].attribute_flag &=
+						(~PART_ATT_SUCCESSFUL_VAL
+						& ~PART_ATT_UNBOOTABLE_VAL);
+
+	if (!attributes_updated)
+		attributes_updated = true;
+
+	/* Update active slot and gpt table */
+	partition_mark_active_slot(new_slot);
+	return;
+}
+
+/*
+	This function returns the most priority and active slot,
+	also you need to update the global state seperately.
+
+*/
+int partition_find_active_slot()
+{
+	unsigned current_priority;
+	int i, count = 0;
+	bool current_bootable_bit;
+	bool current_active_bit;
+	unsigned boot_priority;
+	struct partition_entry *partition_entries = partition_get_partition_entries();
+
+	/* Return current active slot if already found */
+	if (active_slot != INVALID)
+		return active_slot;
+
+	for (boot_priority = MAX_PRIORITY;
+			boot_priority > 0; boot_priority--)
+	{
+		/* Search valid boot slot with highest priority */
+		for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
+		{
+			current_priority = slot_priority(partition_entries, boot_slot_index[i]);
+			current_active_bit = slot_is_active(partition_entries, boot_slot_index[i]);
+			current_bootable_bit = slot_is_bootable(partition_entries, boot_slot_index[i]);
+
+			/* Count number of slots with all attributes as zero */
+			if ( !current_priority &&
+				!current_active_bit &&
+				current_bootable_bit)
+			{
+				count ++;
+				continue;
+			}
+
+#ifdef AB_DEBUG
+	dprintf(INFO, "Slot:Priority:Active:Bootable %s:%d:%d:%d \n",
+						partition_entries[boot_slot_index[i]].name,
+						current_priority,
+						current_active_bit,
+						current_bootable_bit);
+#endif
+			if (boot_priority == current_priority)
+			{
+				if (current_active_bit &&
+					current_bootable_bit)
+				{
+#ifdef AB_DEBUG
+	dprintf(INFO, "Slot (%s) is Valid High Priority Slot\n", SUFFIX_SLOT(i));
+#endif
+					return i;
+				}
+			}
+		}
+
+		/* All slots are zeroed, this is first bootup */
+		/* Marking and trying SLOT 0 as default */
+		if (count == AB_SUPPORTED_SLOTS)
+		{
+			/* Update the priority of the boot slot */
+			partition_entries[boot_slot_index[SLOT_A]].attribute_flag |=
+							((PART_ATT_PRIORITY_VAL |
+							PART_ATT_ACTIVE_VAL |
+							PART_ATT_MAX_RETRY_COUNT_VAL) &
+							(~PART_ATT_SUCCESSFUL_VAL &
+							~PART_ATT_UNBOOTABLE_VAL));
+			if (!attributes_updated)
+				attributes_updated = true;
+			return SLOT_A;
+		}
+	}
+	/* If no valid slot */
+	return INVALID;
+}
+
+static int
+next_active_bootable_slot(struct partition_entry *ptn_entry)
+{
+	int i, slt_index;
+	for (i = 0; i < AB_SUPPORTED_SLOTS; i++)
+	{
+		slt_index = boot_slot_index[i];
+		if (slot_is_bootable(ptn_entry, slt_index))
+			return i;
+	}
+
+	/* NO Bootable slot */
+	panic("ERROR: Unable to find any bootable slot");
+	return 0;
+}
+
+int partition_find_boot_slot()
+{
+	int boot_slot;
+	int slt_index;
+	uint64_t boot_retry_count;
+	struct partition_entry *partition_entries = partition_get_partition_entries();
+
+	boot_retry_count = 0;
+	boot_slot = partition_find_active_slot();
+
+	if (boot_slot == INVALID)
+		goto out;
+
+	slt_index = boot_slot_index[boot_slot];
+
+	/*  Boot if partition flag is set to sucessful */
+	if (partition_entries[slt_index].attribute_flag & PART_ATT_SUCCESSFUL_VAL)
+		goto out;
+
+	boot_retry_count = slot_retry_count(partition_entries, slt_index);
+
+#ifdef AB_DEBUG
+	dprintf(INFO, "Boot Partition:RetryCount %s:%lld\n", partition_entries[slt_index].name,
+							boot_retry_count);
+#endif
+	if (!boot_retry_count)
+	{
+		/* Mark slot invalide and unbootable */
+		partition_entries[slt_index].attribute_flag |=
+					(PART_ATT_UNBOOTABLE_VAL &
+					~PART_ATT_ACTIVE_VAL &
+					~PART_ATT_PRIORITY_VAL);
+
+		partition_switch_slots(boot_slot, next_active_bootable_slot(partition_entries));
+
+		reboot_device(0);
+	}
+	else
+	{
+		/* Do normal boot */
+		/* Decrement retry count */
+		partition_entries[slt_index].attribute_flag =
+					(partition_entries[slt_index].attribute_flag
+					& ~PART_ATT_MAX_RETRY_COUNT_VAL)
+					| ((boot_retry_count-1) << PART_ATT_MAX_RETRY_CNT_BIT);
+
+		if (!attributes_updated)
+			attributes_updated = true;
+
+		goto out;
+	}
+
+out:
+#ifdef AB_DEBUG
+	dprintf(INFO, "Booting SLOT %d\n", boot_slot);
+#endif
+	return boot_slot;
+}
+
+static
+void guid_update(struct partition_entry *partition_entries,
+		unsigned old_index,
+		unsigned new_index)
+{
+	unsigned char tmp_guid[PARTITION_TYPE_GUID_SIZE];
+
+	memcpy(tmp_guid, partition_entries[old_index].type_guid,
+				PARTITION_TYPE_GUID_SIZE);
+	memcpy(partition_entries[old_index].type_guid,
+			partition_entries[new_index].type_guid,
+			PARTITION_TYPE_GUID_SIZE);
+	memcpy(partition_entries[new_index].type_guid, tmp_guid,
+				PARTITION_TYPE_GUID_SIZE);
+	return;
+}
+
+/*
+	Function to swap guids of slots
+*/
+static void
+swap_guid(int old_slot,	int new_slot)
+{
+	unsigned i, j, tmp_strlen;
+	unsigned partition_cnt = partition_get_partition_count();
+	struct partition_entry *partition_entries =
+			partition_get_partition_entries();
+	const char *ptr_pname, *ptr_suffix;
+
+	if ( old_slot == new_slot)
+		return;
+
+	for(i = 0; i < partition_cnt; i++)
+	{
+		ptr_pname = (const char *)partition_entries[i].name;
+
+	        /* Search for suffix in partition name */
+		if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(new_slot))))
+		{
+			for (j = i+1; j < partition_cnt; j++)
+			{
+				tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(new_slot));
+				if (!strncmp((const char*)partition_entries[j].name, ptr_pname, tmp_strlen) &&
+					strstr((const char*)partition_entries[j].name, SUFFIX_SLOT(old_slot)))
+					guid_update(partition_entries, j, i);
+			}
+		}
+		else if ((ptr_suffix = strstr(ptr_pname, SUFFIX_SLOT(old_slot))))
+		{
+			for (j = i+1; j < partition_cnt; j++)
+			{
+				tmp_strlen = strlen(ptr_pname)-strlen(SUFFIX_SLOT(old_slot));
+				if (!strncmp((const char *)partition_entries[j].name, ptr_pname, tmp_strlen) &&
+					strstr((const char *)partition_entries[j].name, SUFFIX_SLOT(new_slot)))
+					guid_update(partition_entries, i, j);
+			}
+		}
+	}
+}
+
+/*
+	Function: Mark the slot to be active and also conditionally
+	update the slot parameters if there is a change.
+*/
+void partition_mark_active_slot(signed slot)
+{
+	if (active_slot == slot)
+		goto out;
+
+	switch (active_slot)
+	{
+		case INVALID:
+			if (slot != SLOT_A)
+				swap_guid(SLOT_A, slot);
+			goto out;
+		default:
+			if (slot == INVALID)
+				swap_guid(active_slot, SLOT_A);
+			else
+				swap_guid(active_slot, slot);
+	}
+	active_slot = slot;
+out:
+	if (attributes_updated)
+		attributes_update();
+	return;
+}
+
+/* Function to find if multislot is supported */
+bool partition_multislot_is_supported()
+{
+	return multislot_support;
+}
+
+/*
+	Function to populate partition meta used
+	for fastboot get var info publication.
+
+	Input partition_entries, partition_count and
+	buffer to fill information.
+
+*/
+int partition_fill_partition_meta(char has_slot_pname[][MAX_GET_VAR_NAME_SIZE],
+					char has_slot_reply[][MAX_RSP_SIZE],
+					int array_size)
+{
+	int i,j,tmp;
+	int count = 0;
+	char *pname = NULL;
+	int pname_size;
+	struct partition_entry *partition_entries =
+				partition_get_partition_entries();
+	int partition_count = partition_get_partition_count();
+	char *suffix_str;
+
+	for (i=0; i<partition_count; i++)
+	{
+		pname = (char *)partition_entries[i].name;
+		pname_size = strlen(pname);
+		suffix_str = NULL;
+ #ifdef AB_DEBUG
+	dprintf(INFO, "Transversing partition %s\n", pname);
+ #endif
+		/* 1. Find partition, if it is A/B enabled. */
+		for ( j = 0; j<AB_SUPPORTED_SLOTS; j++)
+		{
+			suffix_str = strstr(pname, SUFFIX_SLOT(j));
+			if (suffix_str)
+				break;
+		}
+
+		if (suffix_str)
+		{
+			if (!strcmp(suffix_str, SUFFIX_SLOT(SLOT_A)))
+			{
+				/* 2. put the partition name in array */
+				tmp = pname_size-strlen(suffix_str);
+				strlcpy(has_slot_pname[count], pname, tmp+1);
+				strcpy(has_slot_reply[count], " Yes");
+				count++;
+			}
+		}
+		else
+		{
+			strcpy(has_slot_pname[count], pname);
+			strcpy(has_slot_reply[count], " No");
+			count++;
+		}
+
+		/* Avoid over population of array provided */
+		if (count >= array_size)
+		{
+			dprintf(CRITICAL, "ERROR: Not able to parse all partitions\n");
+			return count;
+		}
+	}
+#ifdef AB_DEBUG
+	for (i=0; i<count; i++)
+		dprintf(INFO, "has-slot:%s:%s\n", has_slot_pname[i], has_slot_reply[i]);
+#endif
+	return count;
+}
+
+/*
+	Function to populate the slot meta used
+	for fastboot get var info publication.
+*/
+void partition_fill_slot_meta(struct ab_slot_info *slot_info)
+{
+	int i, current_slot_index;
+	struct partition_entry *ptn_entries = partition_get_partition_entries();
+	char buff[3];
+
+	/* Update slot info */
+	for(i=0; i<AB_SUPPORTED_SLOTS; i++)
+	{
+		current_slot_index = boot_slot_index[i];
+		strcpy(slot_info[i].slot_is_unbootable_rsp,
+				slot_is_bootable(ptn_entries, current_slot_index)?"No":"Yes");
+		strcpy(slot_info[i].slot_is_active_rsp,
+				slot_is_active(ptn_entries, current_slot_index)?"Yes":"No");
+		strcpy(slot_info[i].slot_is_succesful_rsp,
+				slot_is_sucessful(ptn_entries, current_slot_index)?"Yes":"No");
+		itoa(slot_retry_count(ptn_entries, current_slot_index),
+				(unsigned char *)buff, 2, 10);
+		strcpy(slot_info[i].slot_retry_count_rsp, buff);
+	}
+}
+
+/*
+	Function to read and update the attributes of
+	GPT
+*/
+static int
+update_gpt(uint64_t gpt_start_addr,
+		uint64_t gpt_hdr_offset,
+		uint64_t gpt_entries_offset)
+{
+	char *buffer = NULL;
+	char *gpt_entries_ptr, *gpt_hdr_ptr, *tmp = NULL;
+	struct partition_entry *partition_entries = partition_get_partition_entries();
+	uint32_t partition_count = partition_get_partition_count();
+	unsigned i,max_partition_count = 0;
+	unsigned partition_entry_size = 0;
+	uint32_t block_size = mmc_get_device_blocksize();
+	uint32_t crc_val = 0;
+	int ret = 0;
+	uint64_t max_gpt_size_bytes =
+		(PARTITION_ENTRY_SIZE*NUM_PARTITIONS + GPT_HEADER_BLOCKS*block_size);
+
+	buffer = memalign(CACHE_LINE, ROUNDUP(max_gpt_size_bytes, CACHE_LINE));
+	ret = mmc_read(gpt_start_addr, (uint32_t *)buffer,
+				max_gpt_size_bytes);
+	if (ret)
+	{
+		dprintf(CRITICAL, "Failed to read GPT\n");
+		goto out;
+	}
+
+	/* 0. Intialise ptrs for header and entries */
+	gpt_entries_ptr = buffer + gpt_entries_offset*block_size;
+	gpt_hdr_ptr = buffer + gpt_hdr_offset*block_size;
+
+	/* 1. Update attributes_flag of partition entry */
+	tmp = gpt_entries_ptr;
+	for (i=0;i<partition_count;i++)
+	{
+		/* Update the partition attributes */
+		PUT_LONG_LONG(&tmp[ATTRIBUTE_FLAG_OFFSET],
+			partition_entries[i].attribute_flag);
+		memscpy(tmp, PARTITION_TYPE_GUID_SIZE, partition_entries[i].type_guid,
+				PARTITION_TYPE_GUID_SIZE);
+
+		/* point to the next partition entry */
+		tmp += PARTITION_ENTRY_SIZE;
+	}
+
+	/* Calculate and update CRC of partition entries array */
+	max_partition_count =
+		    GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PARTITION_COUNT_OFFSET]);
+	partition_entry_size =
+		    GET_LWORD_FROM_BYTE(&gpt_hdr_ptr[PENTRY_SIZE_OFFSET]);
+	crc_val  = crc32(~0L, gpt_entries_ptr, ((max_partition_count) *
+				(partition_entry_size))) ^ (~0L);
+	PUT_LONG(&gpt_hdr_ptr[PARTITION_CRC_OFFSET], crc_val);
+
+
+	/* Write CRC to 0 before we calculate the crc of the GPT header */
+	crc_val = 0;
+	PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
+	crc_val  = crc32(~0L,gpt_hdr_ptr, GPT_HEADER_SIZE) ^ (~0L);
+	PUT_LONG(&gpt_hdr_ptr[HEADER_CRC_OFFSET], crc_val);
+
+	/* write to mmc */
+	ret = mmc_write(gpt_start_addr, max_gpt_size_bytes, buffer);
+	if (ret)
+	{
+		dprintf(CRITICAL, "Failed to write gpt\n");
+		goto out;
+	}
+out:
+	free(buffer);
+	return ret;
+}
+
+/**
+	Function to update the backup and primary gpt
+	partition.
+**/
+static void attributes_update()
+{
+	uint64_t offset;
+	uint64_t gpt_entries_offset, gpt_hdr_offset;
+	uint64_t gpt_start_addr;
+	int ret;
+	uint32_t block_size = mmc_get_device_blocksize();
+	unsigned max_entries_size_bytes = PARTITION_ENTRY_SIZE*NUM_PARTITIONS;
+	unsigned max_entries_blocks = max_entries_size_bytes/block_size;
+	unsigned max_gpt_blocks = GPT_HEADER_BLOCKS + max_entries_blocks;
+
+	/* Update Primary GPT */
+	offset = 0x01;	/*  offset is 0x1 for primary GPT */
+	gpt_start_addr = offset*block_size;
+	/* Take gpt_start_addr as start and calculate offset from that in block sz*/
+	gpt_hdr_offset = 0; /* For primary partition offset is zero */
+	gpt_entries_offset = GPT_HEADER_BLOCKS;
+
+	ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
+	if (ret)
+	{
+		dprintf(CRITICAL, "Failed to update Primary GPT\n");
+		return;
+	}
+
+	/* Update Secondary GPT */
+	offset = ((mmc_get_device_capacity()/block_size) - max_gpt_blocks);
+	gpt_start_addr = offset*block_size;
+	gpt_hdr_offset = max_entries_blocks;
+	gpt_entries_offset = 0; /* For secondary GPT entries offset is zero */
+
+	ret = update_gpt(gpt_start_addr, gpt_hdr_offset, gpt_entries_offset);
+	if (ret)
+	{
+		dprintf(CRITICAL, "Failed to update Secondary GPT\n");
+		return;
+	}
+	return;
+}
diff --git a/platform/msm_shared/include/ab_partition_parser.h b/platform/msm_shared/include/ab_partition_parser.h
new file mode 100644
index 0000000..2bbddb8
--- /dev/null
+++ b/platform/msm_shared/include/ab_partition_parser.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of The Linux Foundation nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <fastboot.h>
+
+extern const char *suffix_slot[];
+
+#define SUFFIX_SLOT(part_slot) suffix_slot[(part_slot)]
+
+enum
+{
+ SLOT_A = 0,
+ SLOT_B = 1,
+ AB_SUPPORTED_SLOTS = 2,
+ INVALID = -1
+};
+
+/* Structure to print get var info */
+struct ab_slot_info
+{
+	char slot_is_unbootable[MAX_GET_VAR_NAME_SIZE];
+	char slot_is_unbootable_rsp[MAX_RSP_SIZE];
+	char slot_is_active[MAX_GET_VAR_NAME_SIZE];
+	char slot_is_active_rsp[MAX_RSP_SIZE];
+	char slot_is_succesful[MAX_GET_VAR_NAME_SIZE];
+	char slot_is_succesful_rsp[MAX_RSP_SIZE];
+	char slot_retry_count[MAX_GET_VAR_NAME_SIZE];
+	char slot_retry_count_rsp[MAX_RSP_SIZE];
+};
+
+/* A/B support API(s) */
+bool partition_multislot_is_supported();/* Check Multislot is supported */
+bool partition_scan_for_multislot();	/* Calling to scan part. table. */
+void partition_mark_active_slot();	/* Marking slot active */
+void partition_reset_attributes();	/* Resetting slot attr. */
+void partition_fill_slot_meta();	/* Fill slot meta infomation */
+void partition_switch_slots();		/* Switching slots */
+int partition_find_boot_slot();		/* Find bootable partition */
+int partition_find_active_slot();	/* Find current active partition*/
+int partition_fill_partition_meta();	/* Fill partition slot info meta*/
+