| |
================================
Author: taoyuetao
Email: tao_yuetao@yahoo.com.cn
Blog: http://www.eetop.cn/blog/?11145
07-05-09
================================
内核从现在开始就进入了c语言部分,内核启动第二阶段从init/main.c的start_kernel()函数开始到函数结束。
这一阶段对整个系统内存、cache、信号、设备等进行初始化,最后产生新的内核线程init后,
调用cpu_idle()完成内核第二阶段。有很多书籍介绍这一部分的内容,我们这里仅仅讲述与xscale结构相关的部分。
首先我们看一下start_kernel开始部分的源代码
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern char saved_command_line[];
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
lock_kernel();
printk(linux_banner);
setup_arch(&command_line);
printk("Kernel command line: %s\n", saved_command_line);
parse_options(command_line);
trap_init();
init_IRQ();
sched_init();
softirq_init();
time_init();
.......
.....
...
start_kernel使用了asmlinkage进行修饰,该修饰符定义在kernel/include/linux/linkage.h中,如下所示:
#ifdef __cplusplus
#define CPP_ASMLINKAGE extern "C"
#else
#define CPP_ASMLINKAGE
#endif
#if defined __i386__
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
#elif defined __ia64__
#define asmlinkage CPP_ASMLINKAGE __attribute__((syscall_linkage))
#else
#define asmlinkage CPP_ASMLINKAGE
#endif
应为我们使用的是arm平台,所以这些定义没有意义,不过还是简单介绍一下regparm的意思,察看gcc手册,原文
介绍如下:
On the Intel 386, the regparm attribute causes the compiler to pass arguments
number one to number if they are of integral type in registers EAX, EDX,
and ECX instead of on the stack. Functions that take a variable number of
arguments will continue to be passed all of their arguments on the stack.
Beware that on some ELF systems this attribute is unsuitable for global functions
in shared libraries with lazy binding (which is the default). Lazy binding
will send the first call via resolving code in the loader, which might assume
EAX, EDX and ECX can be clobbered, as per the standard calling conventions.
Solaris 8 is affected by this. GNU systems with GLIBC 2.1 or higher,
and FreeBSD, are believed to be safe since the loaders there save all registers.
(Lazy binding can be disabled with the linker or the loader if desired, to avoid
the problem.)
在网上还看到一个比较好的英文说明:
The asmlinkage tag is one other thing that we should observe about this simple function.
This is a #define for some gcc magic that tells the compiler that the function should not
expect to find any of its arguments in registers (a common optimization),
but only on the CPU's stack. Recall our earlier assertion that system_call consumes its
first argument, the system call number, and allows up to four more arguments that are
passed along to the real system call. system_call achieves this feat simply by leaving
its other arguments (which were passed to it in registers) on the stack. All system calls
are marked with the asmlinkage tag, so they all look to the stack for arguments. Of course,
in sys_ni_syscall's case, this doesn't make any difference, because sys_ni_syscall doesn't
take any arguments, but it's an issue for most other system calls. And, because you'll be
seeing asmlinkage in front of many other functions, I thought you should know what it was about.
简单描述一下他的功能:
asmlinkage是个宏,使用它是为了保持参数在stack中。因为从汇编语言到C语言代码参数
的传递是通过stack的,它也可能从stack中得到一些不需要的参数。Asmlinkage将要
解析那些参数。regparm(0)表示不从寄存器传递参数。如果是__attribute__((regparm(3))),
那么调用函数的时候参数不是通过栈传递,而是直接放到寄存器里,被调用函数直接从寄存器取参数。
这一点可以从下面的定义可以看出:
#define fastcall __attribute__((regparm(3)))
这些都必须是在i386平台下才有意义。