意外發現:setprop sys.powerctl reboot,recovery 將重啓進入有菜單選擇界面的recovery模式,在此模式下有root權限,不過要通過串口模式操作。
在系統設置應用裏有恢復出廠設置的菜單,點擊彈出對話框,確認後調用恢復出廠設置廣播:
Settings/src/com/android/tv/settings/device/privacy/PrivacyActivity.java:171
private void onFactoryResetConfirm(ActionBehavior behaviour) {
switch (behaviour) {
case INIT:
setContentAndActionFragments(ContentFragment.newInstance(
ActionType.FACTORY_RESET_CONFIRM.getTitle(getResources()),
getString(R.string.device_reset),
getString(R.string.confirm_factory_reset_description),
R.drawable.ic_settings_backuprestore,
getResources().getColor(R.color.icon_background)),
ActionFragment.newInstance(getFactoryResetConfirmActions()));
break;
case OK:
if (!ActivityManager.isUserAMonkey()) {
Intent resetIntent = new Intent("android.intent.action.MASTER_CLEAR");
if (getIntent().getBooleanExtra(SHUTDOWN_INTENT_EXTRA, false)) {
resetIntent.putExtra(SHUTDOWN_INTENT_EXTRA, true);
}
sendBroadcast(resetIntent);
}
break;
case CANCEL:
getFragmentManager().popBackStack(null, 0);
getFragmentManager().popBackStack(null, 0);
break;
default:
break;
}
}
搜索字段MASTER_CLEAR,frameworks/base/core/res/AndroidManifest.xml裏有註冊receiver
frameworks\base\services\core\java\com\android\server\MasterClearReceiver.java
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
if (!"google.com".equals(intent.getStringExtra("from"))) {
Slog.w(TAG, "Ignoring master clear request -- not from trusted server.");
return;
}
}
final boolean shutdown = intent.getBooleanExtra("shutdown", false);
final String reason = intent.getStringExtra(Intent.EXTRA_REASON);
final boolean wipeExternalStorage = intent.getBooleanExtra(
Intent.EXTRA_WIPE_EXTERNAL_STORAGE, false);
Slog.w(TAG, "!!! FACTORY RESET !!!");
// The reboot call is blocking, so we need to do it on another thread.
Thread thr = new Thread("Reboot") {
@Override
public void run() {
try {
RecoverySystem.rebootWipeUserData(context, shutdown, reason);
Log.wtf(TAG, "Still running after master clear?!");
} catch (IOException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
} catch (SecurityException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
}
}
};
if (wipeExternalStorage) {
// thr will be started at the end of this task.
new WipeAdoptableDisksTask(context, thr).execute();
} else {
thr.start();
}
}
frameworks\base\core\java\android\os\RecoverySystem.java
public static void rebootWipeUserData(Context context, boolean shutdown, String reason)
throws IOException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
throw new SecurityException("Wiping data is not allowed for this user.");
}
final ConditionVariable condition = new ConditionVariable();
Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
android.Manifest.permission.MASTER_CLEAR,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
condition.open();
}
}, null, 0, null, null);
// Block until the ordered broadcast has completed.
condition.block();
String shutdownArg = null;
if (shutdown) {
shutdownArg = "--shutdown_after";
}
String reasonArg = null;
if (!TextUtils.isEmpty(reason)) {
reasonArg = "--reason=" + sanitizeArg(reason);
}
final String localeArg = "--locale=" + Locale.getDefault().toString();
bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
}
private static void bootCommand(Context context, String... args) throws IOException {
RECOVERY_DIR.mkdirs(); // In case we need it
COMMAND_FILE.delete(); // In case it's not writable
LOG_FILE.delete();
FileWriter command = new FileWriter(COMMAND_FILE);
try {
for (String arg : args) {
if (!TextUtils.isEmpty(arg)) {
// MStar Android Patch Begin
StorageManager mStorageManager = context.getSystemService(StorageManager.class);
String cmd = arg;
String label = null;
String uuid = null;
if (cmd.startsWith("--update_package")) {
cmd = arg.substring(17, arg.length() -1);
if (cmd.startsWith("/cache")) {
command.write("--uuid=mstar-cache");
command.write("\n");
command.write("--label=mstar-cache");
command.write("\n");
} else {
StorageVolume vol = mStorageManager.getStorageVolume(new File(cmd));
uuid = "--uuid=" + vol.getUuid();
label = "--label=" + utf8ToUnicode(vol.getFsLabel());
command.write(uuid);
command.write("\n");
command.write(label);
command.write("\n");
}
}
// MStar Android Patch End
command.write(arg);
command.write("\n");
}
}
} finally {
command.close();
}
Log.i(TAG, "bootCommand /cache");
// Having written the command file, go ahead and reboot
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
pm.reboot(PowerManager.REBOOT_RECOVERY);
throw new IOException("Reboot failed (no permissions?)");
}
此時會在安卓設備裏/cache/recovery 目錄清除,且創建command文件,寫入命令:
#/cache/recovery # ls -l
-rw------- system system 55 2018-01-01 08:01 command
#cat command
--wipe_data
--reason=MasterClearConfirm
--locale=zh_CN
然後重啓,重啓還需處理,否則不會進入recovery。ShutdownThread.java:
private static void beginShutdownSequence(Context context) {
synchronized (sIsStartedGuard) {
if (sIsStarted) {
Log.d(TAG, "Shutdown sequence already running, returning.");
return;
}
sIsStarted = true;
}
// Throw up a system dialog to indicate the device is rebooting / shutting down.
ProgressDialog pd = new ProgressDialog(context);
// Path 1: Reboot to recovery and install the update
// Condition: mRebootReason == REBOOT_RECOVERY and mRebootUpdate == True
// (mRebootUpdate is set by checking if /cache/recovery/uncrypt_file exists.)
// UI: progress bar
//
// Path 2: Reboot to recovery for factory reset
// Condition: mRebootReason == REBOOT_RECOVERY
// UI: spinning circle only (no progress bar)
//
// Path 3: Regular reboot / shutdown
// Condition: Otherwise
// UI: spinning circle only (no progress bar)
if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists();
if (mRebootUpdate) {
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_update_prepare));
pd.setMax(100);
pd.setProgressNumberFormat(null);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setProgress(0);
pd.setIndeterminate(false);
} else {
// Factory reset path. Set the dialog message accordingly.
pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
pd.setMessage(context.getText(
com.android.internal.R.string.reboot_to_reset_message));
pd.setIndeterminate(true);
}
} else {
.
.
.
.
// also make sure the screen stays on for better user experience
sInstance.mScreenWakeLock = null;
if (sInstance.mPowerManager.isScreenOn()) {
try {
sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
sInstance.mScreenWakeLock.setReferenceCounted(false);
sInstance.mScreenWakeLock.acquire();
} catch (SecurityException e) {
Log.w(TAG, "No permission to acquire wake lock", e);
sInstance.mScreenWakeLock = null;
}
}
// start the thread that initiates shutdown
sInstance.mHandler = new Handler() {
};
sInstance.start();
}
調到最後一行,sInstance.start(); 啓動線程的運行,進入線程的run方法。
/**
* Makes sure we handle the shutdown gracefully.
* Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
*/
public void run() {
BroadcastReceiver br = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// We don't allow apps to cancel this, so ignore the result.
actionDone();
}
};
/*
* Write a system property in case the system_server reboots before we
* get to the actual hardware restart. If that happens, we'll retry at
* the beginning of the SystemServer startup.
*/
{
String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
}
/*
* If we are rebooting into safe mode, write a system property
* indicating so.
*/
if (mRebootSafeMode) {
SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
}
Log.i(TAG, "Sending shutdown broadcast...");
// First send the high-level shut down broadcast.
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized (mActionDoneSync) {
while (!mActionDone) {
long delay = endTime - SystemClock.elapsedRealtime();
if (delay <= 0) {
Log.w(TAG, "Shutdown broadcast timed out");
break;
} else if (mRebootUpdate) {
int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
sInstance.setRebootProgress(status, null);
}
try {
mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
} catch (InterruptedException e) {
}
}
}
if (mRebootUpdate) {
sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
}
Log.i(TAG, "Shutting down activity manager...");
final IActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);
} catch (RemoteException e) {
}
}
if (mRebootUpdate) {
sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
}
Log.i(TAG, "Shutting down package manager...");
final PackageManagerService pm = (PackageManagerService)
ServiceManager.getService("package");
if (pm != null) {
pm.shutdown();
}
if (mRebootUpdate) {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}
// Shutdown radios.
shutdownRadios(MAX_RADIO_WAIT_TIME);
if (mRebootUpdate) {
sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
}
// Shutdown MountService to ensure media is in a safe state
IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
public void onShutDownComplete(int statusCode) throws RemoteException {
Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
actionDone();
}
};
Log.i(TAG, "Shutting down MountService");
// Set initial variables and time out time.
mActionDone = false;
final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
synchronized (mActionDoneSync) {
try {
final IMountService mount = IMountService.Stub.asInterface(
ServiceManager.checkService("mount"));
if (mount != null) {
mount.shutdown(observer);
} else {
Log.w(TAG, "MountService unavailable for shutdown");
}
} catch (Exception e) {
Log.e(TAG, "Exception during MountService shutdown", e);
}
while (!mActionDone) {
long delay = endShutTime - SystemClock.elapsedRealtime();
if (delay <= 0) {
Log.w(TAG, "Shutdown wait timed out");
break;
} else if (mRebootUpdate) {
int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
(MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
MAX_SHUTDOWN_WAIT_TIME);
status += RADIO_STOP_PERCENT;
sInstance.setRebootProgress(status, null);
}
try {
mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
} catch (InterruptedException e) {
}
}
}
if (mRebootUpdate) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
// If it's to reboot to install update, invoke uncrypt via init service.
uncrypt();
}
rebootOrShutdown(mContext, mReboot, mRebootReason);
}
rebootOrShutdown(mContext, mReboot, mRebootReason);
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
Log.e(TAG, "Reboot failed, will attempt shutdown instead");
} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
// vibrate before shutting down
Vibrator vibrator = new SystemVibrator(context);
try {
vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
} catch (Exception e) {
// Failure to vibrate shouldn't interrupt shutdown. Just log it.
Log.w(TAG, "Failed to vibrate during shutdown.", e);
}
// vibrator is asynchronous so we need to wait to avoid shutting down too soon.
try {
Thread.sleep(SHUTDOWN_VIBRATE_MS);
} catch (InterruptedException unused) {
}
}
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown();
}
PowerManagerService.lowLevelReboot(reason);
/**
* Low-level function to reboot the device. On success, this
* function doesn't return. If more than 20 seconds passes from
* the time a reboot is requested, this method returns.
*
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
*/
public static void lowLevelReboot(String reason) {
if (reason == null) {
reason = "";
}
if (reason.equals(PowerManager.REBOOT_RECOVERY)) {
// If we are rebooting to go into recovery, instead of
// setting sys.powerctl directly we'll start the
// pre-recovery service which will do some preparation for
// recovery and then reboot for us.
SystemProperties.set("ctl.start", "pre-recovery");
} else {
SystemProperties.set("sys.powerctl", "reboot," + reason);
}
try {
Thread.sleep(20 * 1000L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
}
SystemProperties.set("ctl.start", "pre-recovery"); 此處將導致系統重啓,啓動init.rc裏註冊的服務:
service pre-recovery /system/bin/uncrypt --reboot
class main
disabled
oneshot
service pre-recovery /system/bin/uncrypt --reboot system/bin/uncrypt 這個程序會被執行,傳入的參數是--reboot
進入bootable/recovery/uncrypt/uncrypt.cpp
int main(int argc, char** argv) {
const char* input_path;
const char* map_file;
if (argc != 3 && argc != 1 && (argc == 2 && strcmp(argv[1], "--reboot") != 0)) {
fprintf(stderr, "usage: %s [--reboot] [<transform_path> <map_file>]\n", argv[0]);
return 2;
}
// When uncrypt is started with "--reboot", it wipes misc and reboots.
// Otherwise it uncrypts the package and writes the block map.
if (argc == 2) {
printf("\r\n uncrypt to wipe_misc");
if (read_fstab() == NULL) {
return 1;
}
wipe_misc();
reboot_to_recovery();
} else {
// The pipe has been created by the system server.
int status_fd = open(status_file.c_str(), O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR);
if (status_fd == -1) {
ALOGE("failed to open pipe \"%s\": %s\n", status_file.c_str(), strerror(errno));
return 1;
}
if (argc == 3) {
// when command-line args are given this binary is being used
// for debugging.
input_path = argv[1];
map_file = argv[2];
} else {
std::string package;
if (!find_uncrypt_package(package)) {
android::base::WriteStringToFd("-1\n", status_fd);
close(status_fd);
return 1;
}
input_path = package.c_str();
map_file = cache_block_map.c_str();
}
int status = uncrypt(input_path, map_file, status_fd);
if (status != 0) {
android::base::WriteStringToFd("-1\n", status_fd);
close(status_fd);
return 1;
}
android::base::WriteStringToFd("100\n", status_fd);
close(status_fd);
}
return 0;
}
static void reboot_to_recovery() {
ALOGI("rebooting to recovery");
property_set("sys.powerctl", "reboot,recovery");
sleep(10);
ALOGE("reboot didn't succeed?");
}
property_set("sys.powerctl", "reboot,recovery");
sys.powerctl屬性出發開關在init.rc中
on property:sys.powerctl=*
powerctl ${sys.powerctl}
system/core/init/keywords.h
KEYWORD(powerctl, COMMAND, 1, do_powerctl
system/core/init/builtins.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);
}
android_reboot(cmd, 0, reboot_target); 參數爲(ANDROID_RB_RESTART2, 0, "recovery")
system/core/libcutils/android_reboot.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;
}
case ANDROID_RB_RESTART2:
ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, arg);
在用戶空間和內核空間之間,有一個叫做Syscall(系統調用, system call)的中間層,是連接用戶態和內核態的橋樑。這樣即提高了內核的安全型,也便於移植,只需實現同一套接口即可。Linux系統,用戶空間通過向內核空間發出Syscall,產生軟中斷,從而讓程序陷入內核態,執行相應的操作。對於每個系統調用都會有一個對應的系統調用號,比很多操作系統要少很多。
kernel/include/uapi/asm-generic/unistd.h
/* kernel/sys.c */
#define __NR_setpriority 140
__SYSCALL(__NR_setpriority, sys_setpriority)
#define __NR_getpriority 141
__SYSCALL(__NR_getpriority, sys_getpriority)
#define __NR_reboot 142
__SYSCALL(__NR_reboot, sys_reboot)
#define __NR_setregid 143
/* kernel/sys.c */表明是在/* kernel/sys.c */的文件裏定義的方法
宏定義SYSCALL_DEFINEx(xxx,…),展開後對應的方法則是sys_xxx
;
kernel/sys.c
/*
* Reboot system call: for obvious reasons only root may call it,
* and even root needs to set up some magic numbers in the registers
* so that some mistake won't make this reboot the whole machine.
* You can also set the meaning of the ctrl-alt-del-key here.
*
* reboot doesn't sync: do that yourself before calling this.
*/
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 (MP_PLATFORM_PM == 0)
if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
cmd = LINUX_REBOOT_CMD_HALT;
#endif /* MP_PLATFORM_PM */
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:
if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {
ret = -EFAULT;
break;
}
buffer[sizeof(buffer) - 1] = '\0';
kernel_restart(buffer);
break;
#ifdef CONFIG_KEXEC
case LINUX_REBOOT_CMD_KEXEC:
ret = kernel_kexec();
break;
#endif
#ifdef CONFIG_HIBERNATION
case LINUX_REBOOT_CMD_SW_SUSPEND:
ret = hibernate();
break;
#endif
default:
ret = -EINVAL;
break;
}
mutex_unlock(&reboot_mutex);
return ret;
}
kernel_restart(buffer); 參數爲("recovery")
/**
* kernel_restart - reboot the system
* @cmd: pointer to buffer containing command to execute for restart
* or %NULL
*
* Shutdown everything and perform a clean reboot.
* This is not safe to call in interrupt context.
*/
void kernel_restart(char *cmd)
{
extern ptrdiff_t mstar_pm_base;
kernel_restart_prepare(cmd);
migrate_to_reboot_cpu();
syscore_shutdown();
if (!cmd)
printk(KERN_EMERG "Restarting system.\n");
else
printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
#if defined(CONFIG_ARM)
*((volatile unsigned int*) (0xfd000000 + (0x3008 << 1))) = 0x0e00;
*((volatile unsigned int*) (0xfd000000 + (0x300a << 1))) = 0x0727;
#elif defined(CONFIG_ARM64)
*((volatile unsigned int*) (mstar_pm_base + (0x3008 << 1))) = 0x0e00;
*((volatile unsigned int*) (mstar_pm_base + (0x300a << 1))) = 0x0727;
#endif
kmsg_dump(KMSG_DUMP_RESTART);
machine_restart(cmd);
}
machine_restart(cmd); 參數爲("recovery"),machine_restart 函數在很多文件裏都有,具體是哪個文件暫不研究,猜測可能走下面這條路,不過也有可能搞錯了。
arch/arm64/kernel/process.c
void machine_restart(char *cmd)
{
machine_shutdown();
/* Disable interrupts first */
local_irq_disable();
local_fiq_disable();
/* Now call the architecture specific reboot code. */
if (arm_pm_restart)
arm_pm_restart('h', cmd);
/*
* Whoops - the architecture was unable to reboot.
*/
printk("Reboot failed -- System halted\n");
while (1);
}
arm_pm_restart('h', cmd); cmd="recovery"
arch/arm64/kernel/process.c
void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;
EXPORT_SYMBOL_GPL(arm_pm_restart);
arch/arm64/kernel/process.c
#if (MP_PLATFORM_PM == 1)
static void arm_machine_restart(char mode, const char *cmd)
{
/*
* Tell the mm system that we are going to reboot -
* we may need it to insert some 1:1 mappings so that
* soft boot works.
*/
setup_mm_for_reboot();
#ifndef CONFIG_MP_PLATFORM_ARM
/* Clean and invalidate caches */
flush_cache_all();
/* Turn D-cache off */
cpu_cache_off();
/* Push out any further dirty data, and ensure cache is empty */
flush_cache_all();
#endif
/*
* Now call the architecture specific reboot code.
*/
arch_reset(mode, cmd);
}
#else
static void arm_machine_restart(char mode, const char *cmd){}
#endif
kernel\linaro\mstar2\hal\mainz\cpu\arm64\include\mach\system.h
static inline void arch_reset(char mode, const char *cmd)
{
#ifdef CONFIG_SMP
if(magic_number_address != 0)
*(volatile unsigned short *)(magic_number_address) = 0x0;
*(volatile unsigned long*)(REG_PM_MISC_BASE + 0xB8) = 0x79; // reg_top_sw_rst
#endif
#if 0
// set WDT count down timer
*(volatile unsigned long*)(REG_WDT_BASE + 0x10) = BOOT_DELAY_MILLISECOND & 0x0000FFFF;
*(volatile unsigned long*)(REG_WDT_BASE + 0x14) = BOOT_DELAY_MILLISECOND >> 16 ;
#endif
}
arch_reset(mode, cmd); 參數爲('h',"recovery")
#define REG_PM_MISC_BASE (0x2e00UL)
0x2eB8 寫 0x79