在阅读Android 4.4代码的过程中,分析recovery
的过程中遇到函数sys_reboot
的定义,发现其定义过程有大量的宏,因此将其记述于下。
函数sys_reboot
定义
函数sys_reboot
的定义在文件kernel/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 ((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:
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;
}
宏SYSCALL_DEFINE4
定义
看到这里的声明使用到了宏SYSCALL_DEFINE4
,该宏实现在文件kernel/include/linux/syscalls.h
中:
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
宏SYSCALL_DEFINEx
定义
而SYSCALL_DEFINEx
也实现在文件kernel/include/linux/syscalls.h
中:
#define SYSCALL_DEFINEx(x, sname, ...) \
SYSCALL_METADATA(sname, x, __VA_ARGS__) \
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
宏SYSCALL_METADATA
定义
宏SYSCALL_METADATA
定义的定义如下:
#ifdef CONFIG_FTRACE_SYSCALLS
#define SYSCALL_METADATA(sname, nb, ...) \
static const char *types_##sname[] = { \
__MAP(nb,__SC_STR_TDECL,__VA_ARGS__) \
}; \
static const char *args_##sname[] = { \
__MAP(nb,__SC_STR_ADECL,__VA_ARGS__) \
}; \
SYSCALL_TRACE_ENTER_EVENT(sname); \
SYSCALL_TRACE_EXIT_EVENT(sname); \
static struct syscall_metadata __used \
__syscall_meta_##sname = { \
.name = "sys"#sname, \
.syscall_nr = -1, /* Filled in at boot */ \
.nb_args = nb, \
.types = nb ? types_##sname : NULL, \
.args = nb ? args_##sname : NULL, \
.enter_event = &event_enter_##sname, \
.exit_event = &event_exit_##sname, \
.enter_fields = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
}; \
static struct syscall_metadata __used \
__attribute__((section("__syscalls_metadata"))) \
*__p_syscall_meta_##sname = &__syscall_meta_##sname;
#else
#define SYSCALL_METADATA(sname, nb, ...)
#endif
很明显是用于syscall的追踪,故这里不考虑。
宏__SYSCALL_DEFINEx
定义
继续向下,__SYSCALL_DEFINEx
也实现在文件kernel/include/linux/syscalls.h
中:
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
{ \
long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \
__MAP(x,__SC_TEST,__VA_ARGS__); \
__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \
return ret; \
} \
SYSCALL_ALIAS(sys##name, SyS##name); \
static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
宏__MAP
定义
宏__MAP
定义如下:
#define __MAP0(m,...)
#define __MAP1(m,t,a) m(t,a)
#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__)
#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__)
#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__)
#define __MAP(n,...) __MAP##n(__VA_ARGS__)
宏__SC_DECL
定义
宏__SC_DECL
定义如下:
#define __SC_DECL(t, a) t a
宏__PROTECT
定义
宏__PROTECT
定义如下:
#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
总结
根据函数定义:
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
结合SYSCALL_DEFINE4
的定义有:
SYSCALL_DEFINEx(4, _reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
再结合SYSCALL_DEFINEx
则有:
SYSCALL_METADATA(_reboot, 4, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
__SYSCALL_DEFINEx(4, _reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
去掉trace部分,也就是SYSCALL_METADATA
部分,则为:
__SYSCALL_DEFINEx(4, _reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
再结合__SYSCALL_DEFINEx
则有:
asmlinkage long sys_reboot(__MAP(4,__SC_DECL,__VA_ARGS__));
static inline long SYSC_reboot(__MAP(4,__SC_DECL,__VA_ARGS__));
asmlinkage long SyS_reboot(__MAP(4,__SC_LONG,__VA_ARGS__))
{ \
long ret = SYSC_reboot(__MAP(4,__SC_CAST,__VA_ARGS__)); __MAP(4,__SC_TEST,__VA_ARGS__);
__PROTECT(x, ret,__MAP(4,__SC_ARGS,__VA_ARGS__));
return ret;
}
SYSCALL_ALIAS(sys_reboot, SyS_reboot);
static inline long SYSC_reboot(__MAP(4,__SC_DECL,__VA_ARGS__))
再展开__MAP
、__SC_DECL
和__PROTECT
得出:
asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg);
static inline long SYSC_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg);
asmlinkage long SyS_reboot(__MAP(4,__SC_LONG,__VA_ARGS__))
{ \
long ret = SYSC_reboot((int)magic1, (int)magic2, (unsigned int)cmd, (void __user *)arg);
__MAP(4,__SC_TEST,__VA_ARGS__);
__PROTECT(x, ret, magic1, magic2, cmd, arg);
return ret;
}
SYSCALL_ALIAS(sys_reboot, SyS_reboot);
static inline long SYSC_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg)
最终可知,外部调用的sys_reboot
事实上是通过调用SYSC_reboot
来实现的。
网友评论