platform: msm_shared: update for bootloader's requirements

* Add fastboot menu and lock critical menu
* wipe data when device status is changed
  lock->unlock, unlock->lock
  lock_critical->unlock_critical, unlock_critical->lock_critical

Change-Id: I4d8c716cf739a6839ab7a9babc86d99952d205b3
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 736a1f4..08d3cd2 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -855,7 +855,7 @@
 	{
 		case RED:
 #if FBCON_DISPLAY_MSG
-			display_menu_thread(DISPLAY_THREAD_BOOT_STATE);
+			display_bootverify_menu_thread(DISPLAY_MENU_RED);
 			wait_for_users_action();
 #else
 			dprintf(CRITICAL,
@@ -866,7 +866,7 @@
 			break;
 		case YELLOW:
 #if FBCON_DISPLAY_MSG
-			display_menu_thread(DISPLAY_THREAD_BOOT_STATE);
+			display_bootverify_menu_thread(DISPLAY_MENU_YELLOW);
 			wait_for_users_action();
 #else
 			dprintf(CRITICAL,
@@ -1135,7 +1135,7 @@
 	if(boot_verify_get_state() == ORANGE)
 	{
 #if FBCON_DISPLAY_MSG
-		display_menu_thread(DISPLAY_THREAD_BOOT_STATE);
+		display_bootverify_menu_thread(DISPLAY_MENU_ORANGE);
 		wait_for_users_action();
 #else
 		dprintf(CRITICAL,
@@ -1894,17 +1894,71 @@
 	write_device_info(&device);
 }
 
-void set_oem_unlock()
+/* set device unlock value
+ * Must check FRP before call this function
+ * Need to wipe data when unlock status changed
+ * type 0: oem unlock
+ * type 1: unlock critical
+ * status 0: unlock as false
+ * status 1: lock as true
+ */
+void set_device_unlock_value(int type, bool status)
 {
-	if(!device.is_unlocked) {
+	if (type == UNLOCK)
+		device.is_unlocked = status;
+	else if (type == UNLOCK_CRITICAL)
+		device.is_unlock_critical = status;
+
+	write_device_info(&device);
+}
+
+static void set_device_unlock(int type, bool status)
+{
+	int is_unlocked = -1;
+	char response[MAX_RSP_SIZE];
+
+	/* check device unlock status if it is as expected */
+	if (type == UNLOCK)
+		is_unlocked = device.is_unlocked;
+	else if (type == UNLOCK_CRITICAL)
+		is_unlocked = device.is_unlock_critical;
+
+	if (is_unlocked == status) {
+		snprintf(response, sizeof(response), "\tDevice already : %s", (status ? "unlocked!" : "locked!"));
+		fastboot_info(response);
+		fastboot_okay("");
+		return;
+	}
+
+	/* status is true, it means to unlock device */
+	if (status) {
 		if(!is_allow_unlock) {
 			fastboot_fail("oem unlock is not allowed");
 			return;
 		}
 
-		device.is_unlocked = 1;
-		write_device_info(&device);
+#if FBCON_DISPLAY_MSG
+		display_unlock_menu_thread(type);
+		fastboot_okay("");
+		return;
+#else
+		if (type == UNLOCK) {
+			fastboot_fail("Need wipe userdata. Do 'fastboot oem unlock-go'");
+			return;
+		}
+#endif
 	}
+
+	set_device_unlock_value(type, status);
+
+	/* wipe data */
+	struct recovery_message msg;
+
+	snprintf(msg.recovery, sizeof(msg.recovery), "recovery\n--wipe_data");
+	write_misc(0, &msg, sizeof(msg));
+
+	fastboot_okay("");
+	reboot_device(RECOVERY_MODE);
 }
 
 static bool critical_flash_allowed(const char * entry)
@@ -2938,35 +2992,22 @@
 
 void cmd_oem_unlock(const char *arg, void *data, unsigned sz)
 {
-	if(!is_allow_unlock) {
-		fastboot_fail("oem unlock is not allowed");
-		return;
-	}
-
-#if FBCON_DISPLAY_MSG
-	if(!device.is_unlocked)
-		display_menu_thread(DISPLAY_THREAD_UNLOCK);
-	else
-		fastboot_info("Device already unlocked!");
-	fastboot_okay("");
-#else
-	fastboot_fail("Need wipe userdata. Do 'fastboot oem unlock-go'");
-#endif
+	set_device_unlock(UNLOCK, TRUE);
 }
 
 void cmd_oem_unlock_go(const char *arg, void *data, unsigned sz)
 {
-	if(!device.is_unlocked)
-	{
+	if(!device.is_unlocked) {
 		if(!is_allow_unlock) {
 			fastboot_fail("oem unlock is not allowed");
 			return;
 		}
 
-		device.is_unlocked = 1;
-		write_device_info(&device);
+		set_device_unlock_value(UNLOCK, TRUE);
 
+		/* wipe data */
 		struct recovery_message msg;
+
 		snprintf(msg.recovery, sizeof(msg.recovery), "recovery\n--wipe_data");
 		write_misc(0, &msg, sizeof(msg));
 
@@ -2978,18 +3019,7 @@
 
 void cmd_oem_lock(const char *arg, void *data, unsigned sz)
 {
-	struct recovery_message msg;
-	if(device.is_unlocked)
-	{
-		device.is_unlocked = 0;
-		write_device_info(&device);
-		// upon oem lock, reboot to recovery to wipe user data
-		snprintf(msg.recovery, sizeof(msg.recovery), "recovery\n--wipe_data");
-		write_misc(0, &msg, sizeof(msg));
-		fastboot_okay("");
-		reboot_device(RECOVERY_MODE);
-	}
-	fastboot_okay("");
+	set_device_unlock(UNLOCK, FALSE);
 }
 
 void cmd_oem_devinfo(const char *arg, void *data, unsigned sz)
@@ -3018,34 +3048,12 @@
 
 void cmd_flashing_lock_critical(const char *arg, void *data, unsigned sz)
 {
-	if(device.is_unlock_critical) {
-		device.is_unlock_critical = 0;
-		write_device_info(&device);
-	}
-	fastboot_okay("");
+	set_device_unlock(UNLOCK_CRITICAL, FALSE);
 }
 
 void cmd_flashing_unlock_critical(const char *arg, void *data, unsigned sz)
 {
-	if(!device.is_unlock_critical)
-	{
-		if(!is_allow_unlock) {
-			fastboot_fail("oem unlock is not allowed");
-			return;
-		}
-
-		device.is_unlock_critical = 1;
-		write_device_info(&device);
-
-		struct recovery_message msg;
-		snprintf(msg.recovery, sizeof(msg.recovery), "recovery\n--wipe_data");
-		write_misc(0, &msg, sizeof(msg));
-
-		fastboot_okay("");
-		reboot_device(RECOVERY_MODE);
-	}
-	fastboot_okay("");
-
+	set_device_unlock(UNLOCK_CRITICAL, TRUE);
 }
 
 void cmd_preflash(const char *arg, void *data, unsigned sz)
@@ -3296,6 +3304,29 @@
 	}
 }
 
+void get_product_name(unsigned char *buf)
+{
+	snprintf((char*)buf, MAX_RSP_SIZE, "%s",  TARGET(BOARD));
+	return;
+}
+
+void get_bootloader_version(unsigned char *buf)
+{
+	snprintf((char*)buf, MAX_RSP_SIZE, "%s",  device.bootloader_version);
+	return;
+}
+
+void get_baseband_version(unsigned char *buf)
+{
+	snprintf((char*)buf, MAX_RSP_SIZE, "%s", device.radio_version);
+	return;
+}
+
+bool is_device_locked()
+{
+	return device.is_unlocked ? false:true;
+}
+
 /* register commands and variables for fastboot */
 void aboot_fastboot_register_commands(void)
 {
@@ -3540,6 +3571,9 @@
 
 	/* initialize and start fastboot */
 	fastboot_init(target_get_scratch_address(), target_get_max_flash_size());
+#if FBCON_DISPLAY_MSG
+	display_fastboot_menu_thread();
+#endif
 }
 
 uint32_t get_page_size()
diff --git a/app/aboot/devinfo.h b/app/aboot/devinfo.h
index cac64c4..d0e4c73 100644
--- a/app/aboot/devinfo.h
+++ b/app/aboot/devinfo.h
@@ -37,6 +37,11 @@
 #define MAX_PANEL_ID_LEN 64
 #define MAX_VERSION_LEN  64
 
+enum unlock_type {
+	UNLOCK = 0,
+	UNLOCK_CRITICAL,
+};
+
 struct device_info
 {
 	unsigned char magic[DEVICE_MAGIC_SIZE];
diff --git a/include/platform.h b/include/platform.h
index 3a00cdb..609ea7f 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -72,5 +72,9 @@
 int platform_is_msm8996();
 uint64_t platform_get_ddr_start();
 bool platform_use_qmp_misc_settings();
-void set_oem_unlock();
+void set_device_unlock_value(int type, bool status);
+void get_product_name(unsigned char *buf);
+void get_bootloader_version(unsigned char *buf);
+void get_baseband_version(unsigned char *buf);
+bool is_device_locked();
 #endif
diff --git a/platform/msm_shared/display_menu.c b/platform/msm_shared/display_menu.c
index 895db07..bb988df 100644
--- a/platform/msm_shared/display_menu.c
+++ b/platform/msm_shared/display_menu.c
@@ -37,11 +37,12 @@
 #include <boot_verifier.h>
 #include <string.h>
 #include <platform.h>
+#include <smem.h>
+#include <target.h>
+#include <sys/types.h>
+#include <../../../app/aboot/devinfo.h>
 
-#define UNLOCK_OPTION_NUM		2
-#define BOOT_VERIFY_OPTION_NUM		5
-
-static char *unlock_menu_common_msg = "If you unlock the bootloader, "\
+static const char *unlock_menu_common_msg = "If you unlock the bootloader, "\
 				"you will be able to install "\
 				"custom operating system on this phone.\n\n"\
 				"A custom OS is not subject to the same testing "\
@@ -54,25 +55,43 @@
 				"Press the Volume Up/Down buttons to select Yes "\
 				"or No. Then press the Power button to continue.\n";
 
-static char *yellow_warning_msg = "Your device has loaded a diffrent operating "\
-				"system\n\nTo learn more, visit:\n";
+#define YELLOW_WARNING_MSG	"Your device has loaded a diffrent operating "\
+				"system\n\nTo learn more, visit:\n"
 
-static char *orange_warning_msg = "Your device has been unlocker and cann't "\
-				"be trusted\n\nTo learn more, visit:\n";
+#define ORANGE_WARNING_MSG	"Your device has been unlocker and cann't "\
+				"be trusted\n\nTo learn more, visit:\n"
 
-static char *red_warning_msg = "Your device has failed verification and may "\
-				"not work properly\n\nTo learn more, visit:\n";
+#define RED_WARNING_MSG	"Your device has failed verification and may "\
+				"not work properly\n\nTo learn more, visit:\n"
 
 static bool is_thread_start = false;
 struct select_msg_info msg_info;
 
-static char *option_menu[] = {
+#if VERIFIED_BOOT
+struct boot_verify_info {
+	int msg_type;
+	const char *warning_msg;
+};
+
+struct boot_verify_info boot_verify_info[] = {
+			[DISPLAY_MENU_RED] = {FBCON_RED_MSG, RED_WARNING_MSG},
+			[DISPLAY_MENU_YELLOW] = {FBCON_YELLOW_MSG, YELLOW_WARNING_MSG},
+			[DISPLAY_MENU_ORANGE] = {FBCON_ORANGE_MSG, ORANGE_WARNING_MSG}};
+#endif
+
+static char *verify_option_menu[] = {
 		[POWEROFF] = "Power off\n",
 		[RESTART] = "Restart\n",
 		[RECOVER] = "Recovery\n",
 		[FASTBOOT] = "Fastboot\n",
 		[BACK] = "Back to previous page\n"};
 
+static char *fastboot_option_menu[] = {
+		[0] = "START\n",
+		[1] = "Restart bootloader\n",
+		[2] = "Recovery mode\n",
+		[3] = "Power off\n"};
+
 static int big_factor = 2;
 static int common_factor = 1;
 
@@ -152,17 +171,17 @@
 	return str;
 }
 
-void display_unlock_menu(struct select_msg_info *unlock_msg_info)
+void display_unlock_menu(struct select_msg_info *unlock_msg_info, int type)
 {
 	fbcon_clear();
 	memset(unlock_msg_info, 0, sizeof(struct select_msg_info));
 	display_fbcon_menu_message("Unlock bootloader?\n",
 		FBCON_UNLOCK_TITLE_MSG, big_factor);
-	fbcon_draw_line();
+	fbcon_draw_line(FBCON_COMMON_MSG);
 
-	display_fbcon_menu_message(unlock_menu_common_msg,
+	display_fbcon_menu_message((char*)unlock_menu_common_msg,
 		FBCON_COMMON_MSG, common_factor);
-	fbcon_draw_line();
+	fbcon_draw_line(FBCON_COMMON_MSG);
 	unlock_msg_info->option_start[0] = fbcon_get_current_line();
 	display_fbcon_menu_message("Yes\n",
 		FBCON_COMMON_MSG, big_factor);
@@ -170,7 +189,7 @@
 	display_fbcon_menu_message("Unlock bootloader(may void warranty)\n",
 		FBCON_COMMON_MSG, common_factor);
 	unlock_msg_info->option_end[0] = fbcon_get_current_line();
-	fbcon_draw_line();
+	fbcon_draw_line(FBCON_COMMON_MSG);
 	unlock_msg_info->option_start[1] = fbcon_get_current_line();
 	display_fbcon_menu_message("No\n",
 		FBCON_COMMON_MSG, big_factor);
@@ -178,16 +197,19 @@
 	display_fbcon_menu_message("Do not unlock bootloader and restart phone\n",
 		FBCON_COMMON_MSG, common_factor);
 	unlock_msg_info->option_end[1] = fbcon_get_current_line();
-	fbcon_draw_line();
+	fbcon_draw_line(FBCON_COMMON_MSG);
 
-	unlock_msg_info->msg_type = DISPLAY_MENU_UNLOCK;
-	unlock_msg_info->option_num = UNLOCK_OPTION_NUM;
+	if (type == UNLOCK)
+		unlock_msg_info->msg_type = DISPLAY_MENU_UNLOCK;
+	else if (type == UNLOCK_CRITICAL)
+		unlock_msg_info->msg_type = DISPLAY_MENU_UNLOCK_CRITICAL;
+
+	unlock_msg_info->option_num = 2;
 }
 
+#if VERIFIED_BOOT
 void display_boot_verified_menu(struct select_msg_info *msg_info, int type)
 {
-	int msg_type = FBCON_COMMON_MSG;
-	char *warning_msg = NULL;
 	unsigned char* fp_buf = NULL;
 	char fp_str_temp[EVP_MAX_MD_SIZE] = {'\0'};
 	char fp_str[EVP_MAX_MD_SIZE*2] = {'\0'};
@@ -202,21 +224,6 @@
 	fbcon_clear();
 	memset(msg_info, 0, sizeof(struct select_msg_info));
 
-	switch (type) {
-	case DISPLAY_MENU_RED:
-		msg_type = FBCON_RED_MSG;
-		warning_msg = red_warning_msg;
-		break;
-        case DISPLAY_MENU_YELLOW:
-		msg_type = FBCON_YELLOW_MSG;
-		warning_msg = yellow_warning_msg;
-                break;
-	case DISPLAY_MENU_ORANGE:
-		msg_type = FBCON_ORANGE_MSG;
-		warning_msg = orange_warning_msg;
-                break;
-	}
-
 	/* Align Right */
 	str_target = str_align_right(str1, big_factor);
 	if(str_target != NULL)
@@ -230,13 +237,13 @@
 		FBCON_COMMON_MSG, common_factor);
 	display_fbcon_menu_message("press VOLUME keys\n\n",
 		FBCON_SUBTITLE_MSG, common_factor);
-	if(warning_msg != NULL)
-		display_fbcon_menu_message(warning_msg, FBCON_COMMON_MSG, common_factor);
+	if(boot_verify_info[type].warning_msg != NULL)
+		display_fbcon_menu_message((char*)boot_verify_info[type].warning_msg,
+			FBCON_COMMON_MSG, common_factor);
 
 	display_fbcon_menu_message("g.co/placeholder\n",
-		msg_type, common_factor);
+		boot_verify_info[type].msg_type, common_factor);
 
-#if VERIFIED_BOOT
 	if (type == DISPLAY_MENU_YELLOW) {
 		fp_buf = get_boot_fingerprint(&fp_size);
 		if (fp_buf != NULL) {
@@ -253,7 +260,6 @@
 		display_fbcon_menu_message("ID:", FBCON_COMMON_MSG, common_factor);
 		display_fbcon_menu_message(fp_str, FBCON_COMMON_MSG, common_factor);
 	}
-#endif
 
 	display_fbcon_menu_message("\n\nIf no key pressed:\n"\
 		"Your device will boot in 5 seconds\n\n", FBCON_COMMON_MSG, common_factor);
@@ -263,30 +269,105 @@
 		free(str_target);
 	}
 }
+#endif
 
 void display_boot_verified_option(struct select_msg_info *msg_info)
 {
 	int i = 0;
+	int len = 0;
 	fbcon_clear();
 	memset(msg_info, 0, sizeof(struct select_msg_info));
 
+	len = ARRAY_SIZE(verify_option_menu);
 	display_fbcon_menu_message("Options menu:\n\n",
 		FBCON_COMMON_MSG, big_factor);
 	display_fbcon_menu_message("Press volume key to select, and "\
 		"press power key to select\n\n", FBCON_COMMON_MSG, common_factor);
 
-	for (i = 0; i < BOOT_VERIFY_OPTION_NUM; i++) {
-		fbcon_draw_line();
+	for (i = 0; i < len; i++) {
+		fbcon_draw_line(FBCON_COMMON_MSG);
 		msg_info->option_start[i] = fbcon_get_current_line();
-		display_fbcon_menu_message(option_menu[i],
+		display_fbcon_menu_message(verify_option_menu[i],
 			FBCON_COMMON_MSG, common_factor);
 		msg_info->option_bg[i]= fbcon_get_current_bg();
 		msg_info->option_end[i]= fbcon_get_current_line();
 	}
 
-	fbcon_draw_line();
+	fbcon_draw_line(FBCON_COMMON_MSG);
 	msg_info->msg_type = DISPLAY_MENU_MORE_OPTION;
-	msg_info->option_num = BOOT_VERIFY_OPTION_NUM;
+	msg_info->option_num = len;
+}
+
+void display_fastboot_menu(struct select_msg_info *fastboot_msg_info,
+	int option_index)
+{
+	int len;
+	int msg_type = FBCON_COMMON_MSG;
+	char msg_buf[64];
+	char msg[128];
+
+	fbcon_clear();
+	memset(fastboot_msg_info, 0, sizeof(struct select_msg_info));
+
+	len = ARRAY_SIZE(fastboot_option_menu);
+	switch(option_index) {
+		case 0:
+			msg_type = FBCON_GREEN_MSG;
+			break;
+		case 1:
+		case 2:
+			msg_type = FBCON_RED_MSG;
+			break;
+		case 3:
+			msg_type = FBCON_COMMON_MSG;
+			break;
+	}
+	fbcon_draw_line(msg_type);
+	display_fbcon_menu_message(fastboot_option_menu[option_index],
+		msg_type, big_factor);
+	fbcon_draw_line(msg_type);
+	display_fbcon_menu_message("\n\nPress volume key to select, and "\
+		"press power key to select\n\n", FBCON_COMMON_MSG, common_factor);
+
+	display_fbcon_menu_message("FASTBOOT MODE\n", FBCON_RED_MSG, common_factor);
+
+	get_product_name((unsigned char *) msg_buf);
+	snprintf(msg, sizeof(msg), "PRODUCT_NAME - %s\n", msg_buf);
+	display_fbcon_menu_message(msg, FBCON_COMMON_MSG, common_factor);
+
+	memset(msg_buf, 0, sizeof(msg_buf));
+	smem_get_hw_platform_name((unsigned char *) msg_buf, sizeof(msg_buf));
+	snprintf(msg, sizeof(msg), "VARIANT - %s %s\n",
+		msg_buf, target_is_emmc_boot()? "eMMC":"UFS");
+	display_fbcon_menu_message(msg, FBCON_COMMON_MSG, common_factor);
+
+	memset(msg_buf, 0, sizeof(msg_buf));
+	get_bootloader_version((unsigned char *) msg_buf);
+	snprintf(msg, sizeof(msg), "BOOTLOADER VERSION - %s\n",
+		msg_buf);
+	display_fbcon_menu_message(msg, FBCON_COMMON_MSG, common_factor);
+
+	memset(msg_buf, 0, sizeof(msg_buf));
+	get_baseband_version((unsigned char *) msg_buf);
+	snprintf(msg, sizeof(msg), "BASEBAND VERSION - %s\n",
+		msg_buf);
+	display_fbcon_menu_message(msg, FBCON_COMMON_MSG, common_factor);
+
+	memset(msg_buf, 0, sizeof(msg_buf));
+	target_serialno((unsigned char *) msg_buf);
+	snprintf(msg, sizeof(msg), "SERIAL NUMBER - %s\n", msg_buf);
+	display_fbcon_menu_message(msg, FBCON_COMMON_MSG, common_factor);
+
+	snprintf(msg, sizeof(msg), "SECURE BOOT - %s\n",
+		is_secure_boot_enable()? "enabled":"disabled");
+	display_fbcon_menu_message(msg, FBCON_COMMON_MSG, common_factor);
+
+	snprintf(msg, sizeof(msg), "DEVICE STATE - %s\n",
+		is_device_locked()? "locked":"unlocked");
+	display_fbcon_menu_message(msg, FBCON_RED_MSG, common_factor);
+
+	fastboot_msg_info->msg_type = DISPLAY_MENU_FASTBOOT;
+	fastboot_msg_info->option_num = len;
 }
 
 static void display_menu_thread_start(struct select_msg_info *msg_info)
@@ -306,36 +387,40 @@
 	is_thread_start = true;
 }
 
-void display_menu_thread(int type)
+void display_unlock_menu_thread(int type)
 {
-	struct select_msg_info *display_menu_msg_info;
-	display_menu_msg_info = &msg_info;
-	int menu_type = 0;
+	struct select_msg_info *unlock_menu_msg_info;
+	unlock_menu_msg_info = &msg_info;
 
 	set_message_factor();
-	if (type == DISPLAY_THREAD_UNLOCK) {
-		display_unlock_menu(display_menu_msg_info);
+	display_unlock_menu(unlock_menu_msg_info, type);
 
-		dprintf(INFO, "creating oem unlock keys detect thread\n");
-		display_menu_thread_start(display_menu_msg_info);
-	} else {
-	#if VERIFIED_BOOT
-		if (boot_verify_get_state() == ORANGE) {
-			menu_type = DISPLAY_MENU_ORANGE;
-		} else if (boot_verify_get_state() == YELLOW) {
-			menu_type = DISPLAY_MENU_YELLOW;
-		} else if (boot_verify_get_state() == RED) {
-			menu_type = DISPLAY_MENU_RED;
-		}
-		display_boot_verified_menu(display_menu_msg_info, menu_type);
-
-		dprintf(INFO, "creating device state keys detect thread\n");
-		display_menu_thread_start(display_menu_msg_info);
-
-	#else
-		dprintf(CRITICAL, "VERIFIED_BOOT is not enable!!\n");
-		return;
-	#endif
-	}
+	dprintf(INFO, "creating unlock keys detect thread\n");
+	display_menu_thread_start(unlock_menu_msg_info);
 }
 
+void display_fastboot_menu_thread()
+{
+	struct select_msg_info *fastboot_menu_msg_info;
+	fastboot_menu_msg_info = &msg_info;
+
+	set_message_factor();
+	display_fastboot_menu(fastboot_menu_msg_info, 0);
+
+	dprintf(INFO, "creating fastboot menu keys detect thread\n");
+	display_menu_thread_start(fastboot_menu_msg_info);
+}
+
+#if VERIFIED_BOOT
+void display_bootverify_menu_thread(int type)
+{
+	struct select_msg_info *bootverify_menu_msg_info;
+	bootverify_menu_msg_info = &msg_info;
+
+	set_message_factor();
+	display_boot_verified_menu(bootverify_menu_msg_info, type);
+
+	dprintf(INFO, "creating boot verify keys detect thread\n");
+	display_menu_thread_start(bootverify_menu_msg_info);
+}
+#endif
diff --git a/platform/msm_shared/include/display_menu.h b/platform/msm_shared/include/display_menu.h
index 2350fe9..b6167e4 100644
--- a/platform/msm_shared/include/display_menu.h
+++ b/platform/msm_shared/include/display_menu.h
@@ -39,6 +39,8 @@
 	DISPLAY_MENU_RED,
 	DISPLAY_MENU_MORE_OPTION,
 	DISPLAY_MENU_UNLOCK,
+	DISPLAY_MENU_FASTBOOT,
+	DISPLAY_MENU_UNLOCK_CRITICAL,
 };
 
 struct select_msg_info {
@@ -52,14 +54,13 @@
 	bool		msg_volume_key_pressed;
 };
 
-enum display_thread_type {
-	DISPLAY_THREAD_UNLOCK = 0,
-	DISPLAY_THREAD_BOOT_STATE,
-};
-
 void wait_for_users_action(void);
-void display_unlock_menu(struct select_msg_info *msg_info);
+void display_unlock_menu(struct select_msg_info *msg_info, int type);
 void display_boot_verified_menu(struct select_msg_info *msg_info, int type);
 void display_boot_verified_option(struct select_msg_info *msg_info);
-void display_menu_thread(int type);
+void display_fastboot_menu(struct select_msg_info *fastboot_msg_info,
+	int option_index);
+void display_bootverify_menu_thread(int type);
+void display_fastboot_menu_thread();
+void display_unlock_menu_thread(int type);
 #endif				/* __PLATFORM_MSM_SHARED_DISPLAY_MENU_H */
diff --git a/platform/msm_shared/include/menu_keys_detect.h b/platform/msm_shared/include/menu_keys_detect.h
index 31a5661..85bd44e 100644
--- a/platform/msm_shared/include/menu_keys_detect.h
+++ b/platform/msm_shared/include/menu_keys_detect.h
@@ -49,6 +49,7 @@
 	UNLOCK_PAGE = 0,
 	BOOT_VERIFY_PAGE1,
 	BOOT_VERIFY_PAGE2,
+	FASTBOOT_PAGE,
 };
 
 int select_msg_keys_detect(void *param);
diff --git a/platform/msm_shared/menu_keys_detect.c b/platform/msm_shared/menu_keys_detect.c
index d930b6f..28766a7 100644
--- a/platform/msm_shared/menu_keys_detect.c
+++ b/platform/msm_shared/menu_keys_detect.c
@@ -43,6 +43,7 @@
 #include <platform.h>
 #include <reboot.h>
 #include <../../../app/aboot/recovery.h>
+#include <../../../app/aboot/devinfo.h>
 
 #define KEY_DETECT_FREQUENCY		50
 #define KEY_PRESS_TIMEOUT		5000
@@ -94,8 +95,13 @@
 {
 	if (reason == RECOVER) {
 		if (type == DISPLAY_MENU_UNLOCK) {
-			set_oem_unlock();
+			set_device_unlock_value(UNLOCK, TRUE);
+		} else if (type == DISPLAY_MENU_UNLOCK_CRITICAL) {
+			set_device_unlock_value(UNLOCK_CRITICAL, TRUE);
+		}
 
+		if (type == DISPLAY_MENU_UNLOCK ||
+			type == DISPLAY_MENU_UNLOCK_CRITICAL) {
 			/* wipe data */
 			struct recovery_message msg;
 
@@ -217,6 +223,7 @@
 /* continue booting when power key is pressed at boot-verify page1 */
 static uint32_t boot_page1_power_key_func (struct select_msg_info* msg_info,
 	uint32_t option_index){
+	msg_info->msg_power_key_pressed = true;
 	update_device_status(CONTINUE, msg_info->msg_type);
 	return option_index;
 }
@@ -238,6 +245,51 @@
 	return option_index;
 }
 
+static uint32_t fastboot_volume_up_func (struct select_msg_info* msg_info,
+	uint32_t option_index)
+{
+	if (option_index == msg_info->option_num ||
+		option_index == 0) {
+		option_index = msg_info->option_num - 1;
+	} else if (option_index > 0) {
+		option_index--;
+	}
+
+	display_fastboot_menu(msg_info, option_index);
+
+	return option_index;
+}
+
+static uint32_t fastboot_volume_down_func (struct select_msg_info* msg_info,
+	uint32_t option_index)
+{
+	option_index++;
+	if (option_index > msg_info->option_num)
+		option_index = 1;
+	if (option_index == msg_info->option_num)
+		option_index = 0;
+
+	display_fastboot_menu(msg_info, option_index);
+
+	return option_index;
+}
+
+/* update device's status via select option */
+static uint32_t fastboot_power_key_func (struct select_msg_info* msg_info,
+	uint32_t option_index)
+{
+	int device_state[] = {RESTART, FASTBOOT, RECOVER, POWEROFF};
+
+	if(option_index < sizeof(device_state)) {
+		update_device_status(device_state[option_index], msg_info->msg_type);
+	} else {
+		dprintf(CRITICAL, "ERRPR: option index is overflow!!!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
 /* initialize different page's function
  * UNLOCK_PAGE/BOOT_VERIFY_PAGE2:
  *	up_action_func: update select option's background when volume up
@@ -266,6 +318,12 @@
 		menu_volume_down_func,
 		boot_page2_power_key_func,
 	},
+	[FASTBOOT_PAGE] = {
+		fastboot_volume_up_func,
+		fastboot_volume_down_func,
+		fastboot_power_key_func,
+	},
+
 };
 
 void keys_detect_init()
@@ -283,11 +341,15 @@
 		/* get page's index via different message type */
 		switch(msg_info->msg_type) {
 		case DISPLAY_MENU_UNLOCK:
+		case DISPLAY_MENU_UNLOCK_CRITICAL:
 			current_page_index = UNLOCK_PAGE;
 			break;
 		case DISPLAY_MENU_MORE_OPTION:
 			current_page_index = BOOT_VERIFY_PAGE2;
 			break;
+		case DISPLAY_MENU_FASTBOOT:
+			current_page_index = FASTBOOT_PAGE;
+			break;
 		default:
 			current_page_index = BOOT_VERIFY_PAGE1;
 			break;