MTK 增加Factory模式命令

news/2024/10/18 14:26:01/

因为客户需要增加factory mode,而且只能用命令进入,而不让用户感知这个模式的存在,所以决定在系统中增加命令: reboot factory,从而进入factory mode

先看一下reboot命令是如何实现的。

我们在串口输入或者在cmd命令行输入 reboot后,系统会重启,如果后面跟的参数是 bootloader,机器会进入fastboot模式,而如果后面跟的参数是 recovery,则机器进入recovery模式。

一、用户空间部分

查看下reboot命令的代码:

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <cutils/properties.h>
#include <cutils/android_reboot.h>
#include <unistd.h>int main(int argc, char *argv[])
{int ret;size_t prop_len;char property_val[PROPERTY_VALUE_MAX];const char *cmd = "reboot";char *optarg = "";opterr = 0;do {int c;c = getopt(argc, argv, "p");if (c == -1) {break;}switch (c) {case 'p':cmd = "shutdown";break;case '?':fprintf(stderr, "usage: %s [-p] [rebootcommand]\n", argv[0]);exit(EXIT_FAILURE);}} while (1);if(argc > optind + 1) {fprintf(stderr, "%s: too many arguments\n", argv[0]);exit(EXIT_FAILURE);}if (argc > optind)optarg = argv[optind];prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg);if (prop_len >= sizeof(property_val)) {fprintf(stderr, "reboot command too long: %s\n", optarg);exit(EXIT_FAILURE);}ret = property_set(ANDROID_RB_PROPERTY, property_val);if(ret < 0) {perror("reboot");exit(EXIT_FAILURE);}// Don't return early. Give the reboot command time to take effect// to avoid messing up scripts which do "adb shell reboot && adb wait-for-device"while(1) { pause(); }fprintf(stderr, "Done\n");return 0;
}

 

代码比较简单,而且在代码中没有看到直接调用reboot函数或者其他函数来实现reboot。我们可以看到它只是设置了一个属性,这个属性为宏 “ANDROID_RB_PROPERTY”,而这个宏定义为:

#define ANDROID_RB_PROPERTY "sys.powerctl"

由此可见,只是设置了sys.powerctl这个属性,而这个属性会触发什么事情呢?

我们可以再init.rc中找到答案:

on property:sys.powerctl=*powerctl ${sys.powerctl}

这里调用了powerct方法,而我们得知init.rc中,这些叫做关键字,所以我们去init的源码中,找到对应的关键字处理:init/keywords.h

 KEYWORD(powerctl,    COMMAND, 1, do_powerctl)

进而找到do_powerctl函数: 定义在init/builtin.cpp中

int do_powerctl(int nargs, char **args)
{char command[PROP_VALUE_MAX];int res;int len = 0;int cmd = 0;const char *reboot_target;res = expand_props(command, args[1], sizeof(command));if (res) {ERROR("powerctl: cannot expand '%s'\n", args[1]);return -EINVAL;}if (strncmp(command, "shutdown", 8) == 0) {cmd = ANDROID_RB_POWEROFF;len = 8;} else if (strncmp(command, "reboot", 6) == 0) {cmd = ANDROID_RB_RESTART2;len = 6;} else {ERROR("powerctl: unrecognized command '%s'\n", command);return -EINVAL;}if (command[len] == ',') {reboot_target = &command[len + 1];} else if (command[len] == '\0') {reboot_target = "";} else {ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);return -EINVAL;}return android_reboot(cmd, 0, reboot_target);
}

 

通过传入的值分别处理:

reboot 和 shutdown 对应的处理不同,最后执行android_reboot函数

/system/core/libcutils.c

int android_reboot(int cmd, int flags UNUSED, const char *arg)
{int ret;sync();remount_ro();switch (cmd) {case ANDROID_RB_RESTART:ret = reboot(RB_AUTOBOOT);break;case ANDROID_RB_POWEROFF:ret = reboot(RB_POWER_OFF);break;case ANDROID_RB_RESTART2:ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART2, arg);break;default:ret = -1;}return ret;
}

 

这里调用了syscall,这个会触发系统进入内核调用,关于syscall如何陷入内核进行处理,我们参考别的资料

https://blog.csdn.net/rikeyone/article/details/91047118

 

二、内核部分

我们这里直接贴出内核中reboot的实现:

kernel/reboot.c

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,void __user *, arg)
{struct pid_namespace *pid_ns = task_active_pid_ns(current);char buffer[256];int ret = 0;/* We only trust the superuser with rebooting the system. */if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))return -EPERM;/* For safety, we require "magic" arguments. */if (magic1 != LINUX_REBOOT_MAGIC1 ||(magic2 != LINUX_REBOOT_MAGIC2 &&magic2 != LINUX_REBOOT_MAGIC2A &&magic2 != LINUX_REBOOT_MAGIC2B &&magic2 != LINUX_REBOOT_MAGIC2C))return -EINVAL;/** If pid namespaces are enabled and the current task is in a child* pid_namespace, the command is handled by reboot_pid_ns() which will* call do_exit().*/ret = reboot_pid_ns(pid_ns, cmd);if (ret)return ret;/* Instead of trying to make the power_off code look like* halt when pm_power_off is not set do it the easy way.*/if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)cmd = LINUX_REBOOT_CMD_HALT;mutex_lock(&reboot_mutex);switch (cmd) {case LINUX_REBOOT_CMD_RESTART:kernel_restart(NULL);break;case LINUX_REBOOT_CMD_CAD_ON:C_A_D = 1;break;case LINUX_REBOOT_CMD_CAD_OFF:C_A_D = 0;break;case LINUX_REBOOT_CMD_HALT:kernel_halt();do_exit(0);panic("cannot halt");case LINUX_REBOOT_CMD_POWER_OFF:kernel_power_off();do_exit(0);break;case LINUX_REBOOT_CMD_RESTART2:ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);if (ret < 0) {ret = -EFAULT;break;}buffer[sizeof(buffer) - 1] = '\0';kernel_restart(buffer);break;#ifdef CONFIG_KEXECcase LINUX_REBOOT_CMD_KEXEC:ret = kernel_kexec();break;
#endif#ifdef CONFIG_HIBERNATIONcase LINUX_REBOOT_CMD_SW_SUSPEND:ret = hibernate();break;
#endifdefault:ret = -EINVAL;break;}mutex_unlock(&reboot_mutex);return ret;
}

1、检查用户空间传入的magic值

2、根据传入的cmd,分别处理

我们传入的cmd为 LINUX_REBOOT_CMD_RESTART2,接着调用kernel_restart(buffer)函数,buff中的内容为附加的参数 :“bootloader”或者“recovery”,

void kernel_restart(char *cmd)
{kernel_restart_prepare(cmd);migrate_to_reboot_cpu();syscore_shutdown();if (!cmd)pr_emerg("Restarting system\n");elsepr_emerg("Restarting system with command '%s'\n", cmd);kmsg_dump(KMSG_DUMP_RESTART);machine_restart(cmd);
}

这里做kernel restart之前的准备,最后调用machine_restart

arch/arm/process.c

void machine_restart(char *cmd)
{/* Disable interrupts first */local_irq_disable();smp_send_stop();/* Now call the architecture specific reboot code. */pr_emerg("machine_restart, arm_pm_restart(%p)\n", arm_pm_restart);if (arm_pm_restart)arm_pm_restart(reboot_mode, cmd);elsedo_kernel_restart(cmd);/** Whoops - the architecture was unable to reboot.*/printk("Reboot failed -- System halted\n");while (1);
}

当定义了arm_pm_restart函数,就执行arm_pm_restart函数,如果没有定义,则执行do_kernel_restart函数。

我们这里没有定义arm_pm_restart,所以执行do_kernel_restart

void do_kernel_restart(char *cmd)
{atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);
}

这个函数主要是发送通知给到各个注册了reboot通知的模块,我们这里主要看wtd中的通知处理

drivers/watchdog/mediatek/wtd/wd_api.c

这里注册notifier,设置notifier handler

static int __init mtk_arch_reset_init(void)
{int ret;mtk_restart_handler.notifier_call = mtk_arch_reset_handle;mtk_restart_handler.priority = 128;pr_alert("\n register_restart_handler- 0x%p, Notify call: - 0x%p\n",&mtk_restart_handler, mtk_restart_handler.notifier_call);ret = register_restart_handler(&mtk_restart_handler);if (ret)pr_err("ARCH_RESET cannot register mtk_restart_handler!!!!\n");pr_alert("ARCH_RESET register mtk_restart_handler  ok!!!!\n");return ret;
}pure_initcall(mtk_arch_reset_init);

当有通知过来后,执行mtk_restart_handler

static int mtk_arch_reset_handle(struct notifier_block *this, unsigned long mode, void *cmd)
{pr_alert("ARCH_RESET happen!!!\n");arch_reset(mode, cmd);pr_alert("ARCH_RESET end!!!!\n");return NOTIFY_DONE;
}

接下来就是调用arch_reset函数了,也是很重要的函数,可以看到我们传入的“bootloader”或者“recovery”等参数的处理过程

void arch_reset(char mode, const char *cmd)
{
#ifdef CONFIG_FPGA_EARLY_PORTINGreturn;
#elsechar reboot = 0;int res = 0;struct wd_api *wd_api = NULL;res = get_wd_api(&wd_api);pr_alert("arch_reset: cmd = %s\n", cmd ? : "NULL");dump_stack();if (cmd && !strcmp(cmd, "charger")) {/* do nothing */} else if (cmd && !strcmp(cmd, "recovery")) {rtc_mark_recovery();} else if (cmd && !strcmp(cmd, "bootloader")) {rtc_mark_fast();} else if (cmd && !strcmp(cmd, "kpoc")) {
#ifdef CONFIG_MTK_KERNEL_POWER_OFF_CHARGINGrtc_mark_kpoc();
#endif
#if defined(CONFIG_ARCH_MT8163) || defined(CONFIG_ARCH_MT8173)} else if (cmd && !strcmp(cmd, "rpmbpk")) {mtk_wd_SetNonResetReg2(0x0, 1);
#endif} else {reboot = 1;}if (res)pr_err("arch_reset, get wd api error %d\n", res);elsewd_api->wd_sw_reset(reboot);#endif
}

这里对传入的参数分别进行处理,如果参数为 “recovery”,则执行rtc_mark_recovery函数,

drivers/watchdog/mediatek/wtd/mtk_rtc_common.c

void rtc_mark_recovery(void)
{unsigned long flags;struct rtc_time defaulttm;rtc_xinfo("rtc_mark_recovery\n");spin_lock_irqsave(&rtc_lock, flags);hal_rtc_set_spare_register(RTC_FAC_RESET, 0x1);/* Clear alarm setting when doing factory reset. */defaulttm.tm_year = RTC_DEFAULT_YEA - RTC_MIN_YEAR;defaulttm.tm_mon = RTC_DEFAULT_MTH;defaulttm.tm_mday = RTC_DEFAULT_DOM;defaulttm.tm_wday = 1;defaulttm.tm_hour = 0;defaulttm.tm_min = 0;defaulttm.tm_sec = 0;rtc_save_pwron_time(false, &defaulttm, false);hal_rtc_clear_alarm(&defaulttm);spin_unlock_irqrestore(&rtc_lock, flags);
}

 

这里主要是设置RTC_FAC_RESET寄存器的值,等到重启后,机器执行bootloader的时候,取出对应的值来判断该执行哪种模式。

所以,到此之后,我们知道reboot bootloader和reboot recovery在kernel中的执行过程。所以我们如果要想新建一个参数 reboot factory

来使机器进入factory mode,我们只需要在arch_reset中增加对应的处理,并且在RTC中找到一个合适的寄存器来保存值即可

 

修改代码后的补丁:

diff --git a/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h
old mode 100644
new mode 100755
index 2181e99..131ea65
--- a/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h
+++ b/drivers/misc/mediatek/include/mt-plat/mtk_rtc.h
@@ -51,6 +51,7 @@ extern void rtc_mark_recovery(void);extern void rtc_mark_kpoc(void);#endif/*if defined(CONFIG_MTK_KERNEL_POWER_OFF_CHARGING)*/extern void rtc_mark_fast(void);
+extern void rtc_mark_factory_mode(void);extern u16 rtc_rdwr_uart_bits(u16 *val);extern void rtc_bbpu_power_down(void);extern void rtc_read_pwron_alarm(struct rtc_wkalrm *alm);
diff --git a/drivers/misc/mediatek/rtc/mtk_rtc_common.c b/drivers/misc/mediatek/rtc/mtk_rtc_common.c
old mode 100644
new mode 100755
index 87fe9d7..6de7d77
--- a/drivers/misc/mediatek/rtc/mtk_rtc_common.c
+++ b/drivers/misc/mediatek/rtc/mtk_rtc_common.c
@@ -386,6 +386,25 @@ void rtc_mark_fast(void)spin_unlock_irqrestore(&rtc_lock, flags);}+void rtc_mark_factory_mode(void)
+{
+       unsigned long flags;
+
+       printk("rtc_mark_dbgt\n");
+       spin_lock_irqsave(&rtc_lock, flags);
+       hal_rtc_set_spare_register(RTC_ANDROID, 0x5);
+       spin_unlock_irqrestore(&rtc_lock, flags);
+}
+
+void rtc_clr_factory_mode(void)
+{
+       unsigned long flags;
+       printk("rtc_mark_dbgt\n");
+       spin_lock_irqsave(&rtc_lock, flags);
+       hal_rtc_set_spare_register(RTC_ANDROID, 0x0);
+       spin_unlock_irqrestore(&rtc_lock, flags);
+}
+u16 rtc_rdwr_uart_bits(u16 *val){u16 ret = 0;
diff --git a/drivers/watchdog/mediatek/wdk/wd_api.c b/drivers/watchdog/mediatek/wdk/wd_api.c
old mode 100644
new mode 100755
index 7043b25..8aaca5b
--- a/drivers/watchdog/mediatek/wdk/wd_api.c
+++ b/drivers/watchdog/mediatek/wdk/wd_api.c
@@ -606,7 +606,10 @@ void arch_reset(char mode, const char *cmd)} else if (cmd && !strcmp(cmd, "rpmbpk")) {mtk_wd_SetNonResetReg2(0x0, 1);#endif
-       } else {
+       }else if(cmd && !strcmp(cmd, "factory")){
+               rtc_mark_factory_mode();
+       } 
+       else {reboot = 1;}

三、bootloader部分

diff --git a/platform/mt8163/boot_mode.c b/platform/mt8163/boot_mode.c
old mode 100644
new mode 100755
index ba857f1..a75a11a
--- a/platform/mt8163/boot_mode.c
+++ b/platform/mt8163/boot_mode.c
@@ -96,7 +96,7 @@ void boot_mode_select(void)return;}mrdump_check();
-
+       #if defined (HAVE_LK_TEXT_MENU)/*Check RTC to know if system want to reboot to Fastboot*/if(Check_RTC_PDN1_bit13())
@@ -129,6 +129,13 @@ void boot_mode_select(void)g_boot_mode = RECOVERY_BOOT;return;}
+       
+       if(Check_RTC_FAC_Mode())
+       {
+               Set_Clr_RTC_FAC_mode(false);
+               g_boot_mode = FACTORY_BOOT;
+               return;
+       }/*If MISC Write has not completed  in recovery modebefore system reboot, go to recovery mode tofinish remain tasks*/
diff --git a/platform/mt8163/mt_rtc.c b/platform/mt8163/mt_rtc.c
old mode 100644
new mode 100755
index 9a76aa4..1255a19
--- a/platform/mt8163/mt_rtc.c
+++ b/platform/mt8163/mt_rtc.c
@@ -249,6 +249,34 @@ bool Check_RTC_PDN1_bit13(void)return false;}+#define RTC_PDN1_FAC_MODE 0x000f
+bool Check_RTC_FAC_Mode(void)
+{
+       U16 pdn1;
+
+       pdn1 = RTC_Read(RTC_PDN1);
+       if( (pdn1 & RTC_PDN1_ANDROID_MASK)== 0x05 )
+               return true;
+       else
+               return false;
+}
+
+void Set_Clr_RTC_FAC_mode(bool flag)
+{
+       U16 pdn1;
+       
+       rtc_writeif_unlock();
+       //use PDN1 bit13 for LK
+       pdn1 = RTC_Read(RTC_PDN1);
+       if(flag==true)
+               pdn1 = pdn1 | RTC_PDN1_FAC_MODE;
+       else if(flag==false)
+               pdn1 = pdn1 & ~RTC_PDN1_FAC_MODE;
+       RTC_Write(RTC_PDN1, pdn1);
+       rtc_write_trigger();
+}
+
+bool Check_RTC_Recovery_Mode(void){U16 pdn1;

 

 

 


http://www.ppmy.cn/news/394787.html

相关文章

关于简单的factorymode

工厂模式是设计模式里面最基础的&#xff0c;也是最经典的&#xff0c;同时也是最常用的一种模式。它的基本思想就是不管你是什么类型&#xff0c;是要你实现了某个接口&#xff0c;我会在工厂里面进行加工统一处理&#xff0c; 通过某个参数得到需要的实现类。下面给出一个简单…

1_1 FactoryMode 工厂模式

// 定义:定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类&#xff0c; // 工厂模式使得一个类的实例化延迟到了子类 // // 模式举例: // // 模式特点:该模式主要用途是类实例化的延迟&#xff0c;缺点是如果产品 // 过多对应的工厂也会过多&#…

android factorymode下回路测试无声音问题解析

一、 问题描述&#xff1a; 进入factory mode后在进行回路测试项时&#xff0c;第一次测试可以听到声音&#xff0c;但之后再进行测试时无法听到声音。 二、 factory回路测试项代码流程&#xff1a; 主要涉及代码为&#xff1a; mediatek/factory/sr…

android4.4.2 boot,MTK6582+Android4.4.2之bootloader recovery 和factory mode等问题

PMIC:MT6323 1. 侧按键硬件设计 我们设备左边侧按键定义为F7,连接到PMIC MT6323的FCHR_ENB引脚,右边1个电源按键直接接到PMIC的PWRKEY,右边的另一个按键(我们定义为F6)连接到CPU的KCOL0和KROW0引脚 2. DrvGen配置codegen.dws文件 mediatek\dct\DrvGen.exe mediatek…

[Factory mode] 怎么配置工厂模式测试项

[Factory mode] 怎么配置工厂模式测试项 [DESCRIPTION] 修改alps/mediatek/custom/$proj/factory/factory.ini配置工厂模式测项 [KEYWORD] Factory mode test [SOLUTION] alps/mediatek/custom/$proj/factory/factory.ini 可以定制Factory mode测试项&#xff0c;如&#x…

MTK 平台屏蔽 factory mode

环境: MT6737 AndroidN 需求&#xff1a;屏蔽factory mode 修改&#xff1a; vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6735/boot_mode.c 注释这段代码&#xff1a; if (!factory_forbidden) { …

徐静蕾字体效果图

最近发生的有争议的事情太多了&#xff0c;几乎每一天网友们都在争论什么天大的事情。抛开其它的话题不说&#xff0c;电脑里能多一种字体并不是坏事。今天终于找到了传说中的静蕾字体&#xff0c;贴几张图供大家参考。中文效果&#xff1a; 英文和数字效果&#xff1a; 符号…

微软面向大众市场发布Office 2010

2010年6月18日&#xff0c;微软中国在北京面向大众市场正式发布Microsoft Office 2010&#xff0c;用户从今天开始&#xff0c;即可通过电子商务网站、传统软件连锁、新兴家电卖场等多种渠道便捷地购买到正版Office 2010。微软还与众多主流电脑制造商合作&#xff0c;在新出厂的…