因为客户需要增加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;

MTK 增加Factory模式命令相关推荐

  1. 设计模式 — 行为型模式 — 命令模式

    目录 文章目录 目录 命令模式 应用场景 代码示例 命令模式 命令模式的目的是解耦调用操作的对象(调用者)和提供实现的对象(接收者). 命令模式的思路是在调用者和接收者之间插入一个命令类(Comman ...

  2. Java设计模式(1)工厂模式(Factory模式)

    工厂模式定义:提供创建对象的接口. 为何使用工厂模式 工厂模式是我们最常用的模式了,著名的Jive论坛,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见. 为什么工厂模式是如此常用?因 ...

  3. 设计模式-行为型模式-命令模式

    设计模式-行为型模式-命令模式 基础 以一个MIS系统为栗子 MIS 管理信息系统(Management Information System,MIS)是一个以人为主导的,利用计算机硬件.软件和网络设 ...

  4. 本文详细介绍Python 设计模式系列之二: 创建型 Simple Factory 模式(转载)

    源地址:http://doc.chinaunix.net/python/200703/202210.shtml 本文详细介绍Python 设计模式系列之二: 创建型 Simple Factory 模式 ...

  5. 《设计模式详解》行为型模式 - 命令模式

    命令模式 6.3 命令模式 6.3.1 概述 6.3.2 结构 6.3.3 案例实现 6.3.4 优缺点 6.3.5 使用场景 6.3.6 JDK 源码 - Runnable 完整的笔记目录:< ...

  6. Am3358增加Uboot的logo显示 增加Uboot自定义命令控制LCD

    本文的内容如下: 一. 简单介绍一下AM335x的时钟域的概念,然后讲解如何配置LCDC的时钟 二. 讲解LCDC的寄存器的内容和如何根据所选的LCD屏的特性进行时序上的配置 三. 介绍用bmpToR ...

  7. Abstract Factory模式(抽象工厂模式)

    Abstract Factory模式:将关联零件组装成产品. AbstractProduct(抽象产品) 负责定义AbstractFactory角色所生成的抽象零件和产品的接口(API) Abstac ...

  8. FACTORY 模式

    FACTORY 模式 --<敏捷软件开发 原则.模式与实践(c#版)>第29章 柯立芝(1872-1933)美国前总统那个建造工厂的人建造了一座宇宙...... 依赖倒置原则(DIP)告诉 ...

  9. html 黑夜模式,JavaScript_使用javascript为网页增加夜间模式,HTML+CSS:复制代码 代码如下:d - phpStudy...

    使用javascript为网页增加夜间模式 HTML+CSS: .cover{ position:fixed; top: 0px; left: 0px; outline:5000px solid rg ...

  10. oralce 增加表字段命令|oralce 增加表字段类型命令

    oralce 增加表字段命令 语法 alter table 表明 add 字段名 类型 alter table aqcuser add email varchar(36) 转载于:https://ww ...

最新文章

  1. 鱼佬阿水竞赛相声:我是如何2小时杀进排名前10%的!
  2. Java实现简易的文件的迁移器
  3. 使用 ebpf 深入分析容器网络 dup 包问题
  4. 爬虫——————爬取中金所,深交所,上交所期权数据
  5. hausaufgabe--python 20- usage of Closure
  6. 【codevs1867】【Tyvj3508】【BZOJ1041】圆上的整点,数学乱搞
  7. LeetCode Length of Longest Fibonacci Subsequence
  8. LeetCode 542. 01 矩阵
  9. 面试题13. 机器人的运动范围
  10. PLSQL无法连接64位Oracle数据库/Database下拉框为空的解决方法
  11. rgb颜色查询工具_《我的眼睛–图灵识别》第三章:基础:颜色识别
  12. angularJs内置指令63个
  13. 考研数学线上笔记(三):凯哥定积分、棍哥二重积分计算系列课程
  14. 微信抖音快手壁纸小程序三合一源码+后端功能丰富
  15. KITTI数据集解读
  16. dhcp、tftp基础
  17. 金蝶系统提示服务器不是有效的,金蝶服务器不是有效的,请重新设置问题
  18. 混合正弦余弦算法和Lévy飞行的麻雀算法
  19. Android刷windows 10系统,无处不在!安卓手机能刷 Win10 系统了
  20. C# 处理PPT水印(三)—— 在PPT中添加多行(平铺)文本水印效果

热门文章

  1. 抖音文案、声音、设计、视频、图片素材网站
  2. webgl存本地文件_Unity发布WebGL后加载本地文件
  3. 一句话说明sync, fsync, fdatasync的区别
  4. 光纤与光通信-基础知识
  5. Android对话框的详细介绍(提示对话框,自定义对话框)
  6. Linux应用层例程7 CAN 应用编程基础
  7. 高一信息技术 计算机配件的真伪辨别,高一信息技术
  8. 高中教师计算机水平要求,高中信息技术教师考试大纲
  9. 未来计算机的新技术有哪些,科技改变生活!人类未来的十大高科技生活
  10. 计算机二级c简介,二级C语言