Merge "platform: msm_shared: Update kernel early mount dtsi node for UFS/EMMC"
diff --git a/AndroidBoot.mk b/AndroidBoot.mk
index 104f4de..a391249 100644
--- a/AndroidBoot.mk
+++ b/AndroidBoot.mk
@@ -31,6 +31,12 @@
   VERIFIED_BOOT := VERIFIED_BOOT=0
 endif
 
+ifeq ($(EARLY_MOUNT_SUPPORT),true)
+  ENABLE_BOOTDEVICE_MOUNT := ENABLE_BOOTDEVICE_MOUNT=1
+else
+  ENABLE_BOOTDEVICE_MOUNT := ENABLE_BOOTDEVICE_MOUNT=1
+endif
+
 ifeq ($(BOOTLOADER_DISABLE_DISPLAY),true)
   ENABLE_DISPLAY := ENABLE_DISPLAY=0
 else
@@ -73,7 +79,7 @@
 # ELF binary for ABOOT
 TARGET_ABOOT_ELF := $(PRODUCT_OUT)/aboot.elf
 $(TARGET_ABOOT_ELF): ABOOT_CLEAN | $(ABOOT_OUT)
-	$(MAKE) -C bootable/bootloader/lk TOOLCHAIN_PREFIX=$(CROSS_COMPILE) BOOTLOADER_OUT=../../../$(ABOOT_OUT) $(BOOTLOADER_PLATFORM) $(EMMC_BOOT) $(SIGNED_KERNEL) $(VERIFIED_BOOT) $(ENABLE_DISPLAY) $(DEVICE_STATUS) $(BUILD_VARIANT) $(BOARD_NAME) $(ENABLE_VB_ATTEST) $(OSVERSION_IN_BOOTIMAGE)
+	$(MAKE) -C bootable/bootloader/lk TOOLCHAIN_PREFIX=$(CROSS_COMPILE) BOOTLOADER_OUT=../../../$(ABOOT_OUT) $(BOOTLOADER_PLATFORM) $(EMMC_BOOT) $(SIGNED_KERNEL) $(VERIFIED_BOOT) $(ENABLE_DISPLAY) $(ENABLE_BOOTDEVICE_MOUNT) $(DEVICE_STATUS) $(BUILD_VARIANT) $(BOARD_NAME) $(ENABLE_VB_ATTEST) $(OSVERSION_IN_BOOTIMAGE)
 
 # NAND variant output
 TARGET_NAND_BOOTLOADER := $(PRODUCT_OUT)/appsboot.mbn
@@ -102,7 +108,7 @@
 
 # Top level for eMMC variant targets
 $(TARGET_EMMC_BOOTLOADER): emmc_appsbootldr_clean | $(EMMC_BOOTLOADER_OUT) $(INSTALLED_KEYSTOREIMAGE_TARGET)
-	$(MAKE) -C bootable/bootloader/lk TOOLCHAIN_PREFIX=$(CROSS_COMPILE) BOOTLOADER_OUT=../../../$(EMMC_BOOTLOADER_OUT) $(BOOTLOADER_PLATFORM) EMMC_BOOT=1 $(SIGNED_KERNEL) $(VERIFIED_BOOT) $(ENABLE_DISPLAY) $(DEVICE_STATUS) $(BUILD_VARIANT) $(BOARD_NAME) $(ENABLE_VB_ATTEST) $(OSVERSION_IN_BOOTIMAGE)
+	$(MAKE) -C bootable/bootloader/lk TOOLCHAIN_PREFIX=$(CROSS_COMPILE) BOOTLOADER_OUT=../../../$(EMMC_BOOTLOADER_OUT) $(BOOTLOADER_PLATFORM) EMMC_BOOT=1 $(SIGNED_KERNEL) $(VERIFIED_BOOT) $(ENABLE_DISPLAY) $(ENABLE_BOOTDEVICE_MOUNT) $(DEVICE_STATUS) $(BUILD_VARIANT) $(BOARD_NAME) $(ENABLE_VB_ATTEST) $(OSVERSION_IN_BOOTIMAGE)
 
 # Keep build NAND & eMMC as default for targets still using TARGET_BOOTLOADER
 TARGET_BOOTLOADER := $(PRODUCT_OUT)/EMMCBOOT.MBN
diff --git a/lib/libfdt/fdt.c b/lib/libfdt/fdt.c
index 15e66e4..8d99980 100644
--- a/lib/libfdt/fdt.c
+++ b/lib/libfdt/fdt.c
@@ -219,3 +219,31 @@
 	memmove(buf, fdt, fdt_totalsize(fdt));
 	return 0;
 }
+
+int fdt_first_subnode(const void *fdt, int offset)
+{
+        int depth = 0;
+
+        offset = fdt_next_node(fdt, offset, &depth);
+        if (offset < 0 || depth != 1)
+                return -FDT_ERR_NOTFOUND;
+
+        return offset;
+}
+
+int fdt_next_subnode(const void *fdt, int offset)
+{
+        int depth = 1;
+
+        /*
+         * With respect to the parent, the depth of the next subnode will be
+         * the same as the last.
+         */
+        do {
+                offset = fdt_next_node(fdt, offset, &depth);
+                if (offset < 0 || depth < 1)
+                        return -FDT_ERR_NOTFOUND;
+        } while (depth > 1);
+
+        return offset;
+}
diff --git a/lib/libfdt/libfdt.h b/lib/libfdt/libfdt.h
index 667964c..88ea3e3 100644
--- a/lib/libfdt/libfdt.h
+++ b/lib/libfdt/libfdt.h
@@ -136,6 +136,28 @@
 
 int fdt_next_node(const void *fdt, int offset, int *depth);
 
+/**
+ * fdt_first_subnode() - get offset of first direct subnode
+ *
+ * @fdt:        FDT blob
+ * @offset:     Offset of node to check
+ * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
+ */
+int fdt_first_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_next_subnode() - get offset of next direct subnode
+ *
+ * After first calling fdt_first_subnode(), call this function repeatedly to
+ * get direct subnodes of a parent node.
+ *
+ * @fdt:        FDT blob
+ * @offset:     Offset of previous subnode
+ * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
+ * subnodes
+ */
+int fdt_next_subnode(const void *fdt, int offset);
+
 /**********************************************************************/
 /* General functions                                                  */
 /**********************************************************************/
diff --git a/platform/msm_shared/dev_tree.c b/platform/msm_shared/dev_tree.c
index 6a73826..11f9616 100755
--- a/platform/msm_shared/dev_tree.c
+++ b/platform/msm_shared/dev_tree.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015,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
@@ -39,6 +39,11 @@
 #include <kernel/thread.h>
 #include <target.h>
 #include <partial_goods.h>
+#include <boot_device.h>
+#include <platform.h>
+
+#define BOOT_DEV_MAX_LEN        64
+#define NODE_PROPERTY_MAX_LEN   64
 
 struct dt_entry_v1
 {
@@ -49,12 +54,29 @@
 	uint32_t size;
 };
 
+#if ENABLE_BOOTDEVICE_MOUNT
+/* Look up table for fstab node */
+struct fstab_node
+{
+        const char *parent_node;
+        const char *node_prop;
+        const char *device_path_id;
+};
+
+static struct fstab_node fstab_table =
+{
+	"/firmware/android/fstab", "dev", "/soc/"
+};
+#endif
+
 static struct dt_mem_node_info mem_node;
 static int platform_dt_absolute_match(struct dt_entry *cur_dt_entry, struct dt_entry_node *dt_list);
 static struct dt_entry *platform_dt_match_best(struct dt_entry_node *dt_list);
 static int update_dtb_entry_node(struct dt_entry_node *dt_list, uint32_t dtb_info);
 extern int target_is_emmc_boot(void);
 extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
+static int update_fstab_node(void *fdt);
+
 /* TODO: This function needs to be moved to target layer to check violations
  * against all the other regions as well.
  */
@@ -1366,6 +1388,15 @@
 		}
 	}
 
+#if ENABLE_BOOTDEVICE_MOUNT
+	/* Update fstab node */
+	dprintf(SPEW, "Start of fstab node update:%zu ms\n", platform_get_sclk_count());
+	if (update_fstab_node(fdt) != 0) {
+		dprintf(CRITICAL, "ERROR: Cannot update fstab node\n");
+		return ret;
+	}
+	dprintf(SPEW, "End of fstab node update:%zu ms\n", platform_get_sclk_count());
+#endif
 	fdt_pack(fdt);
 
 #if ENABLE_PARTIAL_GOODS_SUPPORT
@@ -1374,3 +1405,101 @@
 
 	return ret;
 }
+
+#if ENABLE_BOOTDEVICE_MOUNT
+/*Update device tree for fstab node */
+static int update_fstab_node(void *fdt)
+{
+	int ret = 0;
+	int str_len = 0;
+	int parent_offset = 0;
+	int subnode_offset = 0;
+	int prop_length = 0;
+	int prefix_string_len = 0;
+	char *node_name = NULL;
+	char *boot_dev_buf = NULL;
+	char *new_str = NULL;
+	char *prefix_str = NULL;
+	char *suffix_str = NULL;
+	const struct fdt_property *prop = NULL;
+
+	/* Find the parent node */
+	parent_offset = fdt_path_offset(fdt, fstab_table.parent_node);
+	if (parent_offset < 0) {
+		dprintf(CRITICAL, "Failed to get parent node: fstab error: %d\n", parent_offset);
+		return -1;
+	}
+	dprintf(SPEW, "Node: %s found.\n", fdt_get_name(fdt, parent_offset, NULL));
+
+	/* Get boot device type */
+	boot_dev_buf = (char *) malloc(sizeof(char) * BOOT_DEV_MAX_LEN);
+	if (!boot_dev_buf) {
+		dprintf(CRITICAL, "Failed to allocate memory for boot device\n");
+		return -1;
+	}
+
+	new_str = (char *) malloc(sizeof(char) * NODE_PROPERTY_MAX_LEN);
+	if (!new_str) {
+		dprintf(CRITICAL, "Failed to allocate memory for node property string\n");
+		return -1;
+	}
+
+
+	platform_boot_dev_cmdline(boot_dev_buf);
+
+	/* Get properties of all sub nodes */
+	for (subnode_offset = fdt_first_subnode(fdt, parent_offset); subnode_offset >= 0; subnode_offset = fdt_next_subnode(fdt, subnode_offset)) {
+		prop = fdt_get_property(fdt, subnode_offset, fstab_table.node_prop, &prop_length);
+		node_name = (char *)(uintptr_t)fdt_get_name(fdt, subnode_offset, NULL);
+		if (!prop) {
+			dprintf(CRITICAL, "Property:%s is not found for sub node:%s\n", fstab_table.node_prop, node_name);
+		} else {
+			dprintf(CRITICAL, "Property:%s found for sub node:%s\tproperty:%s\n", fstab_table.node_prop, node_name, prop->data);
+			/* Pointer to fdt 'dev' property string that needs to update based on the 'androidboot.bootdevice' */
+			memset(new_str, 0, NODE_PROPERTY_MAX_LEN);
+			prefix_str = (char *)prop->data;
+			if (strlen(prefix_str) > NODE_PROPERTY_MAX_LEN) {
+				dprintf(CRITICAL, "Property string length is greater than node property max length\n");
+				continue;
+			}
+			suffix_str = strstr(prefix_str, fstab_table.device_path_id);
+			if (!suffix_str) {
+				dprintf(CRITICAL, "Property is not proper to update\n");
+				continue;
+			}
+			suffix_str += strlen(fstab_table.device_path_id);
+			prefix_string_len = strlen(prefix_str) - (strlen(suffix_str) - 1);
+			suffix_str = strstr((suffix_str + 1), "/");
+			str_len = strlcpy(new_str, prefix_str, prefix_string_len);
+			if (!str_len) {
+				dprintf(CRITICAL, "Property length is not proper to update\n");
+				continue;
+			}
+			str_len = strlcat(new_str, boot_dev_buf, strlen(prefix_str));
+			if (!str_len) {
+				dprintf(CRITICAL, "Property length is not proper to update\n");
+				continue;
+			}
+			str_len = strlcat(new_str, suffix_str, strlen(prefix_str));
+			if (!str_len) {
+				dprintf(CRITICAL, "Property length  is not proper to update\n");
+				continue;
+			}
+			/* Update the new property in the memory */
+			memscpy(prefix_str, strlen(prefix_str), new_str, strlen(new_str) + 1);
+			/* Update the property with new value */
+			ret = fdt_setprop(fdt, subnode_offset, fstab_table.node_prop, (const void *)prefix_str, strlen(prefix_str) + 1);
+			if(ret) {
+				dprintf(CRITICAL, "Failed to update the node with new property\n");
+				continue;
+			}
+			dprintf(CRITICAL, "Updated %s with new property %s\n", node_name, prop->data);
+		}
+	}
+	if (boot_dev_buf)
+	        free(boot_dev_buf);
+	if (new_str)
+		free(new_str);
+        return ret;
+}
+#endif