--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,6 +5,10 @@ ADD_DEFINITIONS(-Os -ggdb -Wall -Werror
 
 SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
 
+ADD_LIBRARY(fstools-bootparam SHARED
+	boot_param.c)
+INSTALL(TARGETS fstools-bootparam LIBRARY DESTINATION lib)
+
 ADD_LIBRARY(fstools SHARED
 		libfstools/snapshot.c
 		libfstools/extroot.c
@@ -15,7 +19,7 @@ ADD_LIBRARY(fstools SHARED
 		libfstools/ubi.c
 		libfstools/rootdisk.c
 		libfstools/find.c)
-TARGET_LINK_LIBRARIES(fstools ubox)
+TARGET_LINK_LIBRARIES(fstools ubox fstools-bootparam)
 INSTALL(TARGETS fstools LIBRARY DESTINATION lib)
 
 ADD_LIBRARY(blkid-tiny SHARED
@@ -75,9 +79,9 @@ INSTALL(TARGETS blockd RUNTIME DESTINATI
 ADD_EXECUTABLE(block block.c probe.c probe-libblkid.c)
 IF(DEFINED CMAKE_UBIFS_EXTROOT)
 	ADD_DEFINITIONS(-DUBIFS_EXTROOT)
-	TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json})
+	TARGET_LINK_LIBRARIES(block blkid-tiny fstools-bootparam dl uci ubox ubus blobmsg_json ubi-utils ${json})
 ELSE(DEFINED CMAKE_UBIFS_EXTROOT)
-	TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ${json})
+	TARGET_LINK_LIBRARIES(block blkid-tiny fstools-bootparam dl uci ubox ubus blobmsg_json ${json})
 ENDIF(DEFINED CMAKE_UBIFS_EXTROOT)
 INSTALL(TARGETS block RUNTIME DESTINATION sbin)
 
--- a/block.c
+++ b/block.c
@@ -47,6 +47,7 @@
 #include <libubus.h>
 
 #include "probe.h"
+#include "boot_param.h"
 
 #define AUTOFS_MOUNT_PATH       "/tmp/run/blockd/"
 
@@ -89,6 +90,9 @@ static LIST_HEAD(devices);
 static int anon_mount, anon_swap, auto_mount, auto_swap, check_fs;
 static unsigned int delay_root;
 
+static char *hide_block_devs[3];
+static uint32_t num_hide_block_devs;
+
 enum {
 	CFG_ANON_MOUNT,
 	CFG_ANON_SWAP,
@@ -498,9 +502,12 @@ static struct probe_info* _probe_path(ch
 	return probe_path(path);
 }
 
+static char* find_mount_point(char *block);
+
 static int _cache_load(const char *path)
 {
 	int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
+	uint32_t i;
 	int j;
 	glob_t gl;
 
@@ -509,8 +516,30 @@ static int _cache_load(const char *path)
 
 	for (j = 0; j < gl.gl_pathc; j++) {
 		struct probe_info *pr = _probe_path(gl.gl_pathv[j]);
-		if (pr)
+		bool skip_curr = false;
+
+		if (pr) {
+			char *mp = find_mount_point(pr->dev);
+			if (mp) {
+				/* Skip blocks mounted as root or overlay */
+				if (!strcmp(mp, "/rom") ||
+				    !strcmp(mp, "/overlay"))
+					continue;
+			}
+
+			for (i = 0; i < num_hide_block_devs; i++) {
+				/* Skip blocks used for dual boot */
+				if (!strcmp(hide_block_devs[i], pr->dev)) {
+					skip_curr = true;
+					break;
+				}
+			}
+
+			if (skip_curr)
+				continue;
+
 			list_add_tail(&pr->list, &devices);
+		}
 	}
 
 	globfree(&gl);
@@ -1801,6 +1830,26 @@ static int main_swapoff(int argc, char *
 	return 0;
 }
 
+static bool add_hide_block_dev(char *path)
+{
+	if (num_hide_block_devs >= ARRAY_SIZE(hide_block_devs))
+		return false;
+
+	hide_block_devs[num_hide_block_devs++] = path;
+	return true;
+}
+
+static void hide_boot_param_dev(const char *name)
+{
+	char *path;
+
+	path = boot_param_get_dev(name);
+	if (path) {
+		if (!add_hide_block_dev(path))
+			free(path);
+	}
+}
+
 int main(int argc, char **argv)
 {
 	char *base = basename(*argv);
@@ -1810,6 +1859,10 @@ int main(int argc, char **argv)
 	ulog_open(-1, -1, "block");
 	ulog_threshold(LOG_NOTICE);
 
+	hide_boot_param_dev("rootfs_data_part");
+	hide_boot_param_dev("boot_rootfs_part");
+	hide_boot_param_dev("upgrade_rootfs_part");
+
 	if (!strcmp(base, "swapon"))
 		return main_swapon(argc, argv);
 
--- a/boot_param.c
+++ b/boot_param.c
@@ -0,0 +1,270 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <glob.h>
+#include <dlfcn.h>
+
+#include <blkid/blkid.h>
+#include <libubox/ulog.h>
+#include "boot_param.h"
+
+#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
+
+#define BOOT_PARAM_STR_MAX_LEN			256
+
+static struct {
+	bool loaded;
+	blkid_probe (*new_probe_from_filename)(const char *);
+	int (*do_safeprobe)(blkid_probe);
+	int (*probe_lookup_value)(blkid_probe, const char *, const char **, size_t *);
+	void (*free_probe)(blkid_probe);
+	int (*probe_enable_partitions)(blkid_probe, int);
+	int (*probe_set_partitions_flags)(blkid_probe, int);
+} libblkid = {};
+
+bool read_boot_param_bool(const char *name)
+{
+	char path[BOOT_PARAM_STR_MAX_LEN], val;
+	size_t len;
+	FILE *f;
+
+	snprintf(path, sizeof(path), "/sys/module/boot_param/parameters/%s",
+		 name);
+
+	f = fopen(path, "rb");
+	if (!f)
+		return false;
+
+	len = fread(&val, 1, 1, f);
+	fclose(f);
+
+	if (len != 1)
+		return false;
+
+	return val == 'Y';
+}
+
+int read_boot_param_string(const char *name, char *val, size_t maxsize)
+{
+	char path[BOOT_PARAM_STR_MAX_LEN];
+	size_t len;
+	FILE *f;
+
+	snprintf(path, sizeof(path), "/sys/module/boot_param/parameters/%s",
+		 name);
+
+	f = fopen(path, "rb");
+	if (!f) {
+		val[0] = 0;
+		return -1;
+	}
+
+	len = fread(val, 1, maxsize, f);
+	fclose(f);
+
+	while (len > 0) {
+		if (val[len - 1] != '\n' && val[len - 1] != '\r')
+			break;
+
+		len--;
+	}
+
+	if (len < maxsize)
+		val[len] = 0;
+
+	return len;
+}
+
+int write_boot_param_string(const char *name, const char *val)
+{
+	size_t wlen, len = strlen(val);
+	char path[BOOT_PARAM_STR_MAX_LEN];
+	FILE *f;
+
+	if (len >= BOOT_PARAM_STR_MAX_LEN)
+		return -1;
+
+	snprintf(path, sizeof(path), "/sys/module/boot_param/parameters/%s",
+		 name);
+
+	f = fopen(path, "wb");
+	if (!f)
+		return -1;
+
+	wlen = fwrite(val, 1, len, f);
+	fclose(f);
+
+	return wlen;
+}
+
+static bool load_libblkid(void)
+{
+	void *lib;
+
+	if (libblkid.loaded)
+		return true;
+
+	lib = dlopen("libblkid.so", RTLD_GLOBAL);
+
+	if (!lib)
+		lib = dlopen("libblkid.so.1", RTLD_GLOBAL);
+
+	if (!lib)
+		return false;
+
+	libblkid.new_probe_from_filename = dlsym(lib, "blkid_new_probe_from_filename");
+	if (!libblkid.new_probe_from_filename)
+		return false;
+
+	libblkid.do_safeprobe = dlsym(lib, "blkid_do_safeprobe");
+	if (!libblkid.do_safeprobe)
+		return false;
+
+	libblkid.probe_lookup_value = dlsym(lib, "blkid_probe_lookup_value");
+	if (!libblkid.probe_lookup_value)
+		return false;
+
+	libblkid.free_probe = dlsym(lib, "blkid_free_probe");
+	if (!libblkid.free_probe)
+		return false;
+
+	libblkid.probe_enable_partitions = dlsym(lib, "blkid_probe_enable_partitions");
+	if (!libblkid.probe_enable_partitions)
+		return false;
+
+	libblkid.probe_set_partitions_flags = dlsym(lib, "blkid_probe_set_partitions_flags");
+	if (!libblkid.probe_set_partitions_flags)
+		return false;
+
+	libblkid.loaded = true;
+	return true;
+}
+
+static char *lookup_block_dev(const char *path, const char *key, bool is_uuid)
+{
+	int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
+	const char *type, *value;
+	char *result = NULL;
+	size_t len;
+	glob_t gl;
+	int i;
+
+	if (glob(path, gl_flags, NULL, &gl) < 0)
+		return NULL;
+
+	type = is_uuid ? "PART_ENTRY_UUID" : "PART_ENTRY_NAME";
+
+	for (i = 0; i < gl.gl_pathc; i++) {
+		blkid_probe pr = libblkid.new_probe_from_filename(gl.gl_pathv[i]);
+		if (!pr)
+			continue;
+
+		libblkid.probe_enable_partitions(pr, 1);
+		libblkid.probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
+
+		if (libblkid.do_safeprobe(pr))
+			goto free_pr;
+
+		if (!libblkid.probe_lookup_value(pr, type, &value, &len)) {
+			if (!strcmp(value, key))
+				result = strdup(gl.gl_pathv[i]);
+		}
+
+	free_pr:
+		libblkid.free_probe(pr);
+
+		if (result)
+			break;
+	}
+
+	globfree(&gl);
+
+	return result;
+}
+
+static char *find_block_dev(const char *key, bool is_uuid)
+{
+	char *devpath = NULL;
+	int i;
+
+	static const char *block_pats[] = {
+		"/dev/loop*",
+		"/dev/mmcblk*",
+		"/dev/sd*",
+		"/dev/hd*",
+		"/dev/md*",
+		"/dev/nvme*",
+		"/dev/vd*",
+		"/dev/xvd*",
+		"/dev/mapper/*",
+	};
+
+	if (!load_libblkid())
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(block_pats); i++) {
+		devpath = lookup_block_dev(block_pats[i], key, is_uuid);
+		if (devpath)
+			break;
+	}
+
+	return devpath;
+}
+
+char *blockdev_parse(const char *name)
+{
+	char *e, *part_dev_path;
+	struct stat st;
+
+	if (!name)
+		return NULL;
+
+	e = strchr(name, '=');
+	if (e) {
+		*e = 0;
+		e++;
+	}
+
+	if (!e) {
+		if (stat(name, &st))
+			return NULL;
+
+		if (!S_ISBLK(st.st_mode))
+			return NULL;
+
+		part_dev_path = strdup(name);
+	} else if (!strcmp(name, "PARTLABEL")) {
+		part_dev_path = find_block_dev(e, false);
+	} else if (!strcmp(name, "PARTUUID")) {
+		if (strlen(e) != 36)
+			return NULL;
+		part_dev_path = find_block_dev(e, true);
+	} else {
+		return NULL;
+	}
+
+	return part_dev_path;
+}
+
+char *boot_param_get_dev(const char *name)
+{
+	char partkey[BOOT_PARAM_STR_MAX_LEN];
+
+	read_boot_param_string(name, partkey, sizeof(partkey));
+
+	if (!partkey[0])
+		return NULL;
+
+	return blockdev_parse(partkey);
+}
--- a/boot_param.h
+++ b/boot_param.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (C) 2022 MediaTek Inc. All rights reserved.
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#ifndef _BOOT_PARAM_H_
+#define _BOOT_PARAM_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+
+bool read_boot_param_bool(const char *name);
+int read_boot_param_string(const char *name, char *val, size_t maxsize);
+int write_boot_param_string(const char *name, const char *val);
+
+char *blockdev_parse(const char *name);
+char *boot_param_get_dev(const char *name);
+
+#endif /* _BOOT_PARAM_H_ */
--- a/libfstools/rootdisk.c
+++ b/libfstools/rootdisk.c
@@ -26,6 +26,7 @@
 
 #include "libfstools.h"
 #include "volume.h"
+#include "../boot_param.h"
 
 #include <linux/loop.h>
 
@@ -42,6 +43,7 @@ struct rootdev_volume {
 	struct volume v;
 	uint64_t offset;
 	char loop_name[32];
+	char *dev_path;
 };
 
 static const char *rootdev;
@@ -109,11 +111,15 @@ static int get_squashfs(struct squashfs_
 
 static bool rootdisk_use_f2fs(struct rootdev_volume *p)
 {
+	const char *dev = rootdev;
 	uint64_t size = 0;
 	bool ret = false;
 	int fd;
 
-	fd = open(rootdev, O_RDONLY);
+	if (p->dev_path)
+		dev = p->dev_path;
+
+	fd = open(dev, O_RDONLY);
 	if (ioctl(fd, BLKGETSIZE64, &size) == 0)
 		ret = size - p->offset > F2FS_MINSIZE;
 	close(fd);
@@ -121,6 +127,30 @@ static bool rootdisk_use_f2fs(struct roo
 	return ret;
 }
 
+static struct volume *find_existed_rootfs_data(void)
+{
+	struct rootdev_volume *p;
+	char *rootfs_data_dev;
+
+	rootfs_data_dev = boot_param_get_dev("rootfs_data_part");
+
+	if (!rootfs_data_dev)
+		return NULL;
+
+	ULOG_NOTE("Using existed rootfs_data device %s\n", rootfs_data_dev);
+
+	write_boot_param_string("rootfs_data_part", rootfs_data_dev);
+
+	p = calloc(1, sizeof(*p));
+	p->v.drv = &rootdisk_driver;
+	p->v.name = "rootfs_data";
+
+	p->offset = 0;
+	p->dev_path = rootfs_data_dev;
+
+	return &p->v;
+}
+
 static struct volume *rootdisk_volume_find(char *name)
 {
 	struct squashfs_super_block sb;
@@ -129,6 +159,9 @@ static struct volume *rootdisk_volume_fi
 	if (strcmp(name, "rootfs_data") != 0)
 		return NULL;
 
+	if (read_boot_param_bool("no_split_rootfs_data"))
+		return find_existed_rootfs_data();
+
 	if (!rootdev)
 		rootdev = get_rootdev("/");
 	if (!rootdev)
@@ -160,12 +193,16 @@ static struct volume *rootdisk_volume_fi
 static int rootdisk_volume_identify(struct volume *v)
 {
 	struct rootdev_volume *p = container_of(v, struct rootdev_volume, v);
+	const char *dev = rootdev;
 	int ret = FS_NONE;
 	uint32_t magic = 0;
 	size_t n;
 	FILE *f;
 
-	f = fopen(rootdev, "r");
+	if (p->dev_path)
+		dev = p->dev_path;
+
+	f = fopen(dev, "r");
 	if (!f)
 		return ret;
 
@@ -265,6 +302,13 @@ static int rootdisk_volume_init(struct v
 	char str[128];
 	int ret = 0;
 
+	if (p->dev_path) {
+		/* Do not create loop device with no_split_rootfs_data set */
+		v->type = BLOCKDEV;
+		v->blk = p->dev_path;
+		goto do_format;
+	}
+
 	if (!p->loop_name[0] && rootdisk_create_loop(p) != 0) {
 		ULOG_ERR("unable to create loop device\n");
 		return -1;
@@ -273,6 +317,7 @@ static int rootdisk_volume_init(struct v
 	v->type = BLOCKDEV;
 	v->blk = p->loop_name;
 
+do_format:
 	switch (rootdisk_volume_identify(v)) {
 	case FS_NONE:
 		ULOG_INFO("rootdisk overlay filesystem has not been formatted yet\n");
--- a/mount_root.c
+++ b/mount_root.c
@@ -23,6 +23,8 @@
 #include "libfstools/libfstools.h"
 #include "libfstools/volume.h"
 
+#include "boot_param.h"
+
 /*
  * Called in the early (PREINIT) stage, when we immediately need some writable
  * filesystem.
@@ -58,6 +60,12 @@ start(int argc, char *argv[1])
 	/* There isn't extroot, so just try to mount "rootfs_data" */
 	volume_init(data);
 	switch (volume_identify(data)) {
+	case -1:
+		/* Use ramoverlay if no "rootfs_data" device found with no_split_rootfs_data set */
+		if (!read_boot_param_bool("no_split_rootfs_data"))
+			break;
+
+		/* fall through */
 	case FS_NONE:
 		ULOG_WARN("no usable overlay filesystem found, using tmpfs overlay\n");
 		return ramoverlay();
