使用adb输入以下命令,可以实现机器的重启,进入到recovery,或者进入到bootloader里
adb reboot
adb reboot recovery
adb reboot bootloader
抽丝剥茧,查看reboot命令的实现
system/core/reboot/reboot.c
#include
#include
#include
#include
#include
#include
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;
}
其中
prop_len = snprintf(property_val, sizeof(property_val), "%s,%s", cmd, optarg);
cmd为shutdown(在加了-p选项时的情况)或者reboot
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);
}
解析完参数后,会设置一个属性值ANDROID_RB_PROPERTY
ANDROID_RB_PROPERTY在哪里定义呢?
查看reboot.c的头文件,猜测是#include
system\core\include\cutils\android_reboot.h 里有定义
#define ANDROID_RB_PROPERTY "sys.powerctl"
在代码里搜索sys.powerctl
system\core\rootdir里有搜索到
on property:sys.powerctl=*
powerctl ${sys.powerctl}
可以看到设置sys.power后这个触发器会导致 powerctl 执行
powerctrl在哪里呢?代码里搜索powerctrl
system\core\init\keywords.h里可以搜索到
KEYWORD(powerctl, COMMAND, 1, do_powerctl)
KEYWORD宏的定义system\core\init\init_parser.h
#define KEYWORD(symbol, flags, nargs, func) \
[ K_##symbol ] = { #symbol, func, nargs + 1, flags, },
展开后
KEYWORD(powerctl, COMMAND, 1, do_powerctl)
即为
K_powerctl = {powerctl,do_powerctl, 2, 2}
lookup_keyword函数里有
case 'p':
if (!strcmp(s, "owerctl")) return K_powerctl;
parse_line_action会执行
kw = lookup_keyword(args[0]);
...............
n = kw_nargs(kw);
if (nargs < n) {
parse_error(state, "%s requires %d %s\n", args[0], n - 1,
n > 2 ? "arguments" : "argument");
return;
}
cmd = malloc(sizeof(*cmd) + sizeof(char*) * nargs);
cmd->func = kw_func(kw);
cmd->line = state->line;
cmd->filename = state->filename;
cmd->nargs = nargs;
memcpy(cmd->args, args, sizeof(char*) * nargs);
list_add_tail(&act->commands, &cmd->clist);
最终会导致do_powercrl执行
do_powercrl定义在system/core/init/builtins.c
do_powerctl
........................
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;
}
.....................
android_reboot(cmd, 0, reboot_target)
会调用android_reboot
android_reboot定义在system\core\libcutils\android_reboot.c
int android_reboot(int cmd, int flags UNUSED, 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;
}
最终会调用reboot或者syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, arg);
这两个最终都会调用到__reboot
对于32bit在目录bionic\libc\arch-arm\syscalls\__reboot.S
/* Generated by gensyscalls.py. Do not edit. */
#include
ENTRY(__reboot)
mov ip, r7
ldr r7, =__NR_reboot
swi #0
mov r7, ip
cmn r0, #(MAX_ERRNO + 1)
bxls lr
neg r0, r0
b __set_errno_internal
END(__reboot)
对于64bit在目录bionic\libc\arch-arm64\syscalls\__reboot.S
/* Generated by gensyscalls.py. Do not edit. */
#include
ENTRY(__reboot)
mov x8, __NR_reboot
svc #0
cmn x0, #(MAX_ERRNO + 1)
cneg x0, x0, hi
b.hi __set_errno_internal
ret
END(__reboot)
.hidden __reboot
无论32位还是64位最终都会调用到kernel里的reboot系统调用
kernel/reboot.c
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
.........
switch (cmd) {
.................
case LINUX_REBOOT_CMD_RESTART:
kernel_restart(NULL);
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;
.....................
调用kernel_restart(buffer);
void kernel_restart(char *cmd)
{
kernel_restart_prepare(cmd);
migrate_to_reboot_cpu();
syscore_shutdown();
if (!cmd)
pr_emerg("Restarting system\n");
else
pr_emerg("Restarting system with command '%s'\n", cmd);
kmsg_dump(KMSG_DUMP_RESTART);
machine_restart(cmd);
}
调用machine_restart
machine_restart
...........
if (arm_pm_restart)
arm_pm_restart(reboot_mode, cmd);
如果arm_pm_restart不空的话调用arm_pm_restart
drivers\power\reset\msm-poweroff.c
在msm_restart_probe里设置了arm_pm_restart和pm_power_off
pm_power_off = do_msm_poweroff;
arm_pm_restart = do_msm_restart;
static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
msm_restart_prepare(cmd);
scm_disable_sdi();
halt_spmi_pmic_arbiter();
deassert_ps_hold();
mdelay(10000);
调用msm_restart_prepare
static void msm_restart_prepare(const char *cmd)
if (cmd != NULL) {
if (!strncmp(cmd, "bootloader", 10)) {
qpnp_pon_set_restart_reason(
PON_RESTART_REASON_BOOTLOADER);
__raw_writel(0x77665500, restart_reason);
} else if (!strncmp(cmd, "recovery", 8)) {
qpnp_pon_set_restart_reason(
PON_RESTART_REASON_RECOVERY);
__raw_writel(0x77665502, restart_reason);
} else if (!strcmp(cmd, "rtc")) {
qpnp_pon_set_restart_reason(
PON_RESTART_REASON_RTC);
__raw_writel(0x77665503, restart_reason);
} else if (!strcmp(cmd, "dm-verity device corrupted")) {
qpnp_pon_set_restart_reason(
PON_RESTART_REASON_DMVERITY_CORRUPTED);
__raw_writel(0x77665508, restart_reason);
} else if (!strcmp(cmd, "dm-verity enforcing")) {
qpnp_pon_set_restart_reason(
PON_RESTART_REASON_DMVERITY_ENFORCE);
__raw_writel(0x77665509, restart_reason);
} else if (!strcmp(cmd, "keys clear")) {
qpnp_pon_set_restart_reason(
PON_RESTART_REASON_KEYS_CLEAR);
__raw_writel(0x7766550a, restart_reason);
} else if (!strncmp(cmd, "oem-", 4)) {
unsigned long code;
int ret;
ret = kstrtoul(cmd + 4, 16, &code);
if (!ret)
__raw_writel(0x6f656d00 | (code & 0xff),
restart_reason);
} else if (!strncmp(cmd, "edl", 3)) {
enable_emergency_dload_mode();
} else {
__raw_writel(0x77665501, restart_reason);
}
}
flush_cache_all();
drivers\platform\msm\qpnp-power-on.c
int qpnp_pon_set_restart_reason(enum pon_restart_reason reason)
{
int rc = 0;
struct qpnp_pon *pon = sys_reset_dev;
if (!pon)
return 0;
if (!pon->store_hard_reset_reason)
return 0;
rc = qpnp_pon_masked_write(pon, QPNP_PON_SOFT_RB_SPARE(pon),
PON_MASK(7, 2), (reason << 2));
if (rc)
dev_err(&pon->spmi->dev,
"Unable to write to addr=%x, rc(%d)\n",
QPNP_PON_SOFT_RB_SPARE(pon), rc);
return rc;
}
其中#define QPNP_PON_SOFT_RB_SPARE(pon) ((pon)->base + 0x8F)
在msm_restart_probe里设置了restart_reason
msm_restart_probe
of_find_compatible_node(NULL, NULL,
"qcom,msm-imem-restart_reason");
restart_reason = of_iomap(np, 0);
在dtsi里有定义(比如msm8917.dtsi)
qcom,msm-imem@8600000 {
compatible = "qcom,msm-imem";
reg = <0x08600000 0x1000>; /* Address and size of IMEM */
ranges = <0x0 0x08600000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
..............
restart_reason@65c {
compatible = "qcom,msm-imem-restart_reason";
reg = <0x65c 4>;
};
. ..........
可知在msm8917里restart_reason保存在0x860065c地址里
PS:这段地址在msm8917里落在IMEM的区间里
写在这里的值,restart_reason在lk里会进行读取,来判断restart的原因
app/aboot/aboot.c
#if USE_PON_REBOOT_REG
reboot_mode = check_hard_reboot_mode();
#else
reboot_mode = check_reboot_mode();
#endif
if (reboot_mode == RECOVERY_MODE)
{
boot_into_recovery = 1;
}
else if(reboot_mode == FASTBOOT_MODE)
{ if(target_build_variant_user())
boot_into_fastboot = 0;
else
boot_into_fastboot = true;
}
else if(reboot_mode == ALARM_BOOT)
{
boot_reason_alarm = true;
}
#if VERIFIED_BOOT
#if !VBOOT_MOTA
else if (reboot_mode == DM_VERITY_ENFORCING)
{
device.verity_mode = 1;
write_device_info(&device);
}
#if ENABLE_VB_ATTEST
else if (reboot_mode == DM_VERITY_EIO)
#else
else if (reboot_mode == DM_VERITY_LOGGING)
#endif
{
device.verity_mode = 0;
write_device_info(&device);
}
else if (reboot_mode == DM_VERITY_KEYSCLEAR)
{
if(send_delete_keys_to_tz())
ASSERT(0);
}
如果是用pmic的寄存器保存的话,使用check_hard_reboot_mode
unsigned check_hard_reboot_mode(void)
{
uint8_t hard_restart_reason = 0;
uint8_t value = 0;
/* Read reboot reason and scrub it
* Bit-5, bit-6 and bit-7 of SOFT_RB_SPARE for hard reset reason
*/
value = pm8x41_reg_read(PON_SOFT_RB_SPARE);
hard_restart_reason = value >> 5;
pm8x41_reg_write(PON_SOFT_RB_SPARE, value & 0x1f);
return hard_restart_reason;
}
其中PON_SOFT_RB_SPARE定义为
#define PON_SOFT_RB_SPARE 0x88F
如果是在IMEM里保存的话,使用check_reboot_mode();
unsigned check_reboot_mode(void)
{
uint32_t restart_reason = 0;
/* Read reboot reason and scrub it */
restart_reason = readl(RESTART_REASON_ADDR);
writel(0x00, RESTART_REASON_ADDR);
return restart_reason;
}
对于msm8917定义
#define RESTART_REASON_ADDR (MSM_SHARED_IMEM_BASE + 0x65C)
#define MSM_SHARED_IMEM_BASE 0x08600000
所以RESTART_REASON_ADDR 的值为0x0860065C,与kernel里是一致的