本文主要讲解“linux内核是否有main函数”,感兴趣的朋友不妨看看。本文介绍的方法简单、快速、实用。让主机频道带你了解一下linux内核是否有main函数!
Linux内核具有主要功能;main函数是程序的入口,main是应用程序和操作系统约定的一个接口名,所以linux中每个应用程序的第一个函数必须是main。
linux内核源代码主要功能分析
这几天我一直在纠结:
主要功能是程序的入口。一个程序启动后,应该是通过bootloader初始化后,通过main函数进入C语言的世界,但是linux的每个应用都是从main函数开始的。linux下有很多应用,所以有很多主要的应用。然后bootloader就知道要跳转到哪个main了多个main编译怎么可能不冲突?
在网上搜索了很久,渐渐有些明白了:
1、主要功能是C语言的入口,这句话没错;但这句话只是约定,并不是不可改变的铁律!从程序更本质的汇编代码来看,只是大家都同意跳转到一个名为“main & quot以...为标签;言下之意,这个标签也可以改名。比如linux的C语言入口是start _ kernel();从这个标签地址开始,C语言就是世界。用main这个名字只是因为大家都同意。不遵守约定就可以玩,就像苹果的充电线和别人的不一样。
2.编译时没有多个主函数!虽然每个应用都有一个主要功能(从应用的角度来说,应用的入口是主要功能);但是应用是独立编译的,不会一起编译,所以操作系统内核更不可能和应用一起编译!所以根本不存在多重主冲突!!可能是统一操作系统和应用程序的接口,也可能是main是侧面影响下的程序入口的说法。main是应用程序和操作系统之间约定的接口名称!所以linux中每个应用的第一个函数一定是main。除非你改变内核调度的接口。
3.linux应用的安装和启动也可以和我们日常使用的Windows相比较。Windows应用程序的安装其实就是把一些执行文件复制到指定的文件夹中(从便携应用来看),点击运行。linux下也是如此。将编译后的bin文件放入指定的文件夹目录,然后开始执行命令。
/*
* linux/init/main.c
*
*版权所有(C) 1991,1992 Linus Torvalds
*
* GK 1995年2月5日—更改为支持通过NFS装载根文件系统
*增加了initrd & amp沃纳·阿尔梅斯伯格& amp汉斯·勒曼,2月39日;96
*如果gcc是旧的,就早点抱怨,避免虚假的内核- Paul Gortmaker,May & # 3996
* init的简化启动:迈克尔·格里菲斯·grif@acm.org
* start _ kernel-& gt;rest _ init-& gt;Kernel_init创建用户初始化pid=1。
-& gt;kthread管理内核线程pid=x
-& gt;Pid=0,这是一个空闲线程。
在rest_init中,会创建kernel_init线程,负责创建用户init进程,完成工作后,会
化身为空闲线程
*/
# include & ltLinux/types . h & gt;
# include & ltLinux/module . h & gt;
# include & ltLinux/proc _ fs . h & gt;
# include & ltLinux/kernel . h & gt;
# include & ltLinux/syscalls . h & gt;
# include & ltLinux/stack protector . h & gt;
# include & ltLinux/string . h & gt;
# include & ltLinux/ctype . h & gt;
# include & ltLinux/delay . h & gt;
# include & ltLinux/io port . h & gt;
# include & ltLinux/init . h & gt;
# include & ltLinux/initrd . h & gt;
# include & ltLinux/bootmem . h & gt;
# include & ltLinux/acpi . h & gt;
# include & ltLinux/tty . h & gt;
# include & ltLinux/percpu . h & gt;
# include & ltLinux/kmod . h & gt;
# include & ltLinux/vmalloc . h & gt;
# include & ltLinux/kernel _ stat . h & gt;
# include & ltLinux/start _ kernel . h & gt;
# include & ltLinux/security . h & gt;
# include & ltLinux/SMP . h & gt;
# include & ltLinux/profile . h & gt;
# include & ltLinux/rcu update . h & gt;
# include & ltLinux/module param . h & gt;
# include & ltLinux/kall syms . h & gt;
# include & ltLinux/write back . h & gt;
# include & ltLinux/CPU . h & gt;
# include & ltLinux/CPU set . h & gt;
# include & ltLinux/cgroup . h & gt;
# include & ltLinux/EFI . h & gt;
# include & ltLinux/tick . h & gt;
# include & ltLinux/interrupt . h & gt;
# include & ltLinux/task stats _ kern . h & gt;
# include & ltLinux/delay acct . h & gt;
# include & ltLinux/unistd . h & gt;
# include & ltLinux/rmap . h & gt;
# include & ltLinux/mem policy . h & gt;
# include & ltLinux/key . h & gt;
# include & ltLinux/buffer _ head . h & gt;
# include & ltLinux/page _ cgroup . h & gt;
# include & ltLinux/debug _ locks . h & gt;
# include & ltLinux/debug objects . h & gt;
# include & ltLinux/lock dep . h & gt;
# include & ltLinux/kmem leak . h & gt;
# include & ltLinux/PID _ namespace . h & gt;
# include & ltLinux/device . h & gt;
# include & ltLinux/kthread . h & gt;
# include & ltLinux/sched . h & gt;
# include & ltLinux/signal . h & gt;
# include & ltLinux/IDR . h & gt;
# include & ltLinux/kgdb . h & gt;
# include & ltLinux/ftrace . h & gt;
# include & ltLinux/async . h & gt;
# include & ltLinux/kmem check . h & gt;
# include & ltLinux/SFI . h & gt;
# include & ltLinux/shmem _ fs . h & gt;
# include & ltLinux/slab . h & gt;
# include & ltLinux/perf _ event . h & gt;
# include & ltASM/io . h & gt;
# include & ltASM/bugs . h & gt;
# include & ltASM/setup . h & gt;
# include & ltASM/sections . h & gt;
# include & ltASM/cache flush . h & gt;
#ifdef CONFIG_X86_LOCAL_APIC
# include & ltASM/SMP . h & gt;
#endif
静态int kernel _ init(void *);
extern void init _ IRQ(void);
extern void fork_init(无符号长整型);
外部void MCA _ init(void);
外部void sbus _ init(void);
外部void prio _ tree _ init(void);
extern void radix _ tree _ init(void);
#ifndef CONFIG_DEBUG_RODATA
静态内联void mark_rodata_ro(void) { }
#endif
#ifdef配置_TC
外部void TC _ init(void);
#endif
/*
* Debug helper:通过这个标志我们知道我们在& # 39;早期启动代码& # 39;
*只有启动处理器在IRQ禁用的情况下运行。这意味着
*两件事——在标志被清除之前,不得使能IRQ
IRQ禁用时不允许的操作在
*标志已设置。
*/
bool early _ boot _ irqs _ disabled _ _ read _ mosly;
枚举system _ States system _ state _ _ read _ mosly;
EXPORT_SYMBOL(系统状态);
/*
*引导命令行参数
*/
#define MAX_INIT_ARGS配置_初始化_环境_参数_限制
#define MAX_INIT_ENVS配置_初始化_环境_参数_限制
外部void time _ init(void);
/*默认延迟时间初始化为空。archs可以在以后覆盖它。*/
void(* _ _ initdata late _ time _ init)(void);
extern void softirq _ init(void);
/*由特定于arch的代码保存的未接触的命令行。*/
char _ _ initdata boot _ COMMAND _ LINE[COMMAND _ LINE _ SIZE];
/*未接触的已保存命令行(例如for /proc) */
char * saved _ command _ line
/*用于参数解析的命令行*/
静态char * static _ command _ line
静态字符*执行命令;
静态char * ramdisk _ execute _ command
/*
*如果设置,这是对重置底层的驱动程序的指示
*设备,否则驱动程序可能会
*依靠BIOS并跳过复位操作。
*
*如果内核在不可靠的环境中启动,这很有用。
*适用于ex。先前内核崩溃的情况,BIOS已经
*跳过,设备将处于未知状态。
*/
无符号整数reset _ devices
EXPORT_SYMBOL(重置_设备);
静态int _ _ init set _ reset _ devices(char * str)
{
重置设备= 1;
返回1;
}
_ _安装(& quot重置设备& quot,set _ reset _ devices);
静态常量char * argv _ INIT[MAX _ INIT _ ARGS+2]= { & quot;初始化& quot,NULL,};
const char * envp _ INIT[MAX _ INIT _ ENVS+2]= { & quot;HOME =/& quot;,& quotTERM = linux & quot,NULL,};
static const char *panic_later,* panic _ param
extern const struct OBS _ kernel _ param _ _ setup _ start[],_ _ setup _ end[];
static int _ _ init obsolete _ check setup(char * line)
{
const struct OBS _ kernel _ param * p;
int had _ early _ param = 0;
p = _ _ setup _ start
做{
int n = strlen(p-& gt;str);
if (parameqn(line,p->str,n)) {
如果(p->;早期){
/*已经在parse_early_param中完成?
*(需要参数部分的精确匹配)。
*继续迭代,因为我们可以有早期
*同名的参数和_ _设置8( */
if(line[n]= = & # 39;\0'| | line[n]= = & # 39;=')
had _ early _ param = 1;
} else if(!p->;setup_func) {
printk(KERN _ WARNING & quot;参数%s已过时。
"被忽略\ n & quot,p-& gt;str);
返回1;
} else if(p-& gt;setup_func(line + n))
返回1;
}
p++;
} while(p & lt;_ _ setup _ end);
return had _ early _ param
}
/*
*这将在大约2个月之后开始(注意初始换档),并将
*即使最初太大,仍然可以工作,只是时间会稍微长一点
*/
无符号长循环_ per _ jiffy =(1 & lt;& lt12);
EXPORT _ SYMBOL(loops _ per _ jiffy);
静态int __init debug_kernel(char *str)
{
console _ loglevel = 10
返回0;
}
静态int __init quiet_kernel(char *str)
{
console _ log level = 4;
返回0;
}
早期参数(& quot调试,debug _ kernel);
早期参数(& quot安静& quot,quiet _ kernel);
static int _ _ init log level(char * str)
{
int newlevel
/*
*仅在通过正确设置时更新loglevel值,
*防止盲目崩溃(当loglevel设置为0时)
*很难调试
*/
if(get _ option(& amp;str & amp;新级别)){
console _ loglevel = newlevel
返回0;
}
return-EINVAL;
}
早期参数(& quot日志级别& quot,log level);
/*将NUL术语改回& quot= & quot,使& quot参数& quot整串。*/
static int _ _ init repair _ env _ string(char * param,char *val)
{
if (val) {
/* param=val或param = & quotval & quot?*/
if (val == param+strlen(param)+1)
val[-1]= & # 39;=';
else if(val = = param+strlen(param)+2){
val[-2]= & # 39;=';
memmove(val-1,val,strlen(val)+1);
val-;
}否则
BUG();
}
返回0;
}
/*
*未知的引导选项被传递给init,除非它们看起来像
*未使用的参数(modprobe将在/proc/cmdline中找到它们)。
*/
static int _ _ init unknown _ boot option(char * param,char *val)
{
repair_env_string(param,val);
/*处理过时样式的参数*/
if (obsolete_checksetup(param))
返回0;
/*未使用的模块参数。*/
if (strchr(param,& # 39;。')& amp& amp(!val || strchr(param,& # 39;。')& ltval))
返回0;
如果(慌_后)
返回0;
if (val) {
/*环境选项*/
无符号int I;
for(I = 0;envp _ init[I];i++) {
if (i ==最大初始ENVS) {
panic _ later = & quot“%s”处的引导环境变量太多。";
panic _ param = param
}
如果(!strncmp(param,envp_init[i],val - param))
打破;
}
envp _ init[I]= param;
}否则{
/*命令行选项*/
无符号int I;
for(I = 0;argv _ init[I];i++) {
if (i ==最大初始ARGS) {
panic _ later = & quot“%s”处的启动初始化变量太多。";
panic _ param = param
}
}
argv _ init[I]= param;
}
返回0;
}
静态int __init init_setup(char *str)
{
无符号int I;
execute _ command = str
/*
*如果LILO用默认命令行引导我们,
*它前置& quot自动& quot在整个命令行之前
shell认为它应该执行一个具有这样名称的脚本。
*所以我们忽略所有输入的参数_before_ init=...[MJ]
*/
for(I = 1;我& lt马克斯_ INIT _ ARGS;i++)
argv _ init[I]= NULL;
返回1;
}
_ _安装(& quotinit = & quot,init _ setup);
static int _ _ init rdinit _ setup(char * str)
{
无符号int I;
ramdisk _ execute _ command = str
/*参见& quot自动& quotinit_setup中的注释*/
for(I = 1;我& lt马克斯_ INIT _ ARGS;i++)
argv _ init[I]= NULL;
返回1;
}
_ _安装(& quotrdinit = & quot,rdinit _ setup);
#ifndef CONFIG_SMP
static const unsigned int setup _ max _ CPU = NR _ CPU;
#ifdef CONFIG_X86_LOCAL_APIC
静态void __init smp_init(void)
{
init _初始化_单处理器();
}
#否则
#define smp_init() do { } while (0)
#endif
静态内联void setup_nr_cpu_ids(void) { }
静态内联void SMP _ prepare _ CPU(unsigned int max CPU){ }
#endif
/*
*我们需要存储未接触过的命令行以供将来参考。
*我们还需要存储被触摸的命令行,因为参数
*解析是就地执行的,我们应该允许组件
*存储名称/值的参考,以供将来参考。
*/
静态void _ _ init setup _命令行(char *command_line)
{
saved _ command _ line = alloc _ bootmem(strlen(boot _ command _ line)+1);
static _ command _ line = alloc _ bootmem(strlen(command _ line)+1);
strcpy (saved_command_line,boot _ command _ line);
strcpy (static_command_line,命令行);
}
/*
*我们需要在一个非__init函数中完成,否则会出现竞争情况
*在根线程和init线程之间可能会导致start_kernel
*在根线程继续之前被free_initmem获取
* cpu_idle。
*
* gcc-3.4不小心内联了这个函数,所以使用noinline。
*/
static _ _ initdata DECLARE _ COMPLETION(kthreadd _ done);
静态非线性void __init_refok rest_init(void)
{
int pid
rcu _ scheduler _ starting();//读取-复制更新开始。
/*
*但是,我们需要首先生成init,以便它获得pid 1
init任务将最终希望创建kthreads,如果
*我们在创建kthreadd之前对其进行调度,将会出错。
*创建一个内核线程,线程函数为kernel_init,pid=1,内核进程。
*/
kernel_thread(kernel_init,NULL,CLONE _ FS | CLONE _ SIGHAND);
//numa策略设置
numa_default_policy()。
//全局链表kthread_create_list中的kthread内核线程全部运行。
//kthread线程管理和调度其他内核线程。
PID = kernel _ thread(kthread,NULL,CLONE _ FS | CLONE _ FILES);
rcu _ read _ lock();
//通过pid,ini_pid_ns获取kthreadd地址。
kthreadd _ task = find _ task _ by _ PID _ ns(PID,& ampinit _ PID _ ns);
rcu _ read _ unlock();
//在kthreadd _ done条件下通知kernel_init线程。
完成(& ampkthreadd _ done);
/*
*引导空闲线程必须执行schedule()
*至少一次让事情运转起来:
*空闲线程初始化
*/
init_idle_bootup_task(当前);
//抢占被禁用
schedule _ preempt _ disabled();
/*调用cpu_idle并禁用抢占*/
CPU _ idle();
}
/*检查早期参数。*/
static int _ _ init do _ early _ param(char * param,char *val)
{
const struct OBS _ kernel _ param * p;
for(p = _ _ setup _ start;p & lt_ _ setup _ endp++) {
如果((p-& gt;早期& amp& ampparameq(param,p-& gt;str)) ||
(strcmp(param,& quot控制台& quot)= = 0 & amp& amp
strcmp(p-& gt;str,& quotearlycon & quot) == 0)
) {
如果(p->;setup_func(val)!= 0)
printk(内核_警告
"畸形的早期选项& # 39;% s & # 39\ n & quot,param);
}
}
/*我们接受现阶段的一切。*/
返回0;
}
void _ _ init parse _ early _ options(char * cmdline)
{
parse _ args(& quot;早期期权& quot,cmdline,NULL,0,0,0,do _ early _ param);
}
/* Arch代码在早期调用这个函数,如果没有调用,就在其他解析之前调用。*/
void _ _ init parse _ early _ param(void)
{
static _ _ initdata int done = 0;
static _ _ initdata char tmp _ cmdline[COMMAND _ LINE _ SIZE];
如果(完成)
返回;
/*全部落入do_early_param。*/
strlcpy(tmp_cmdline,boot_command_line,COMMAND _ LINE _ SIZE);
parse _ early _ options(tmp _ cmdline);
done = 1;
}
/*
*激活第一个处理器。
*/
静态void __init boot_cpu_init(void)
{
int CPU = SMP _ processor _ id();
/*标记启动cpu & quot现在& quot,& quot在线& quotSMP和UP情况下的etc */
set_cpu_online(cpu,true);
set_cpu_active(cpu,true);
set_cpu_present(cpu,true);
set_cpu_possible(cpu,true);
}
void _ _ init _ _ weak SMP _ setup _ processor _ id(void)
{
}
void _ _ init _ _弱线程_信息_缓存_初始化(void)
{
}
/*
*设置内核内存分配器
*/
静态void __init mm_init(void)
{
/*
* page_cgroup需要连续的页面,
*大于MAX_ORDER,除非SPARSEMEM。
*/
page _ cgroup _ init _ flat mem();
mem _ init();
kmem _ cache _ init();
percpu _ init _ late();
pg table _ cache _ init();
VM alloc _ init();
}
ASM link void _ _ init start _ kernel(void)
{
char * command _ line
extern const struct kernel _ param _ _ start _ _ _ param[],_ _ stop _ _ _ param[];
/*
*需要尽早运行,以初始化
* lockdep哈希:
*/
//初始化两个哈希表——锁依赖验证器(内核依赖的关系表)。
lock dep _ init();
SMP _ setup _ processor _ id();//空函数
调试对象早期初始化();//初始化内核调试相关性
/*
*尽快设置初始金丝雀:
*/
boot _ init _ stack _ canary();//初始化堆栈溢出保护
//控制组初始化-cgroup-资源任务分组管理
cgroup _ init _ early();
local _ IRQ _ disable();//关闭中断
early _ boot _ irqs _ disabled = true
/*
*中断仍然被禁用。然后做必要的设置
*启用它们
*/
tick _ init();//时钟初始化
boot _ CPU _ init();//开始cpu初始化。
page _ address _ init();//页面初始化
printk(KERN _ NOTICE & quot;% s & quot,Linux _ banner);
setup _ arch(& amp;command _ line);//与架构相关的初始化
mm_init_owner。init _ mm & amp;init _任务);//内存管理初始化
mm _ init _ cpumask(& amp;init _ mm);//内存管理初始化
setup_command_line(命令行);//处理命令行(保存2份)
setup _ NR _ CPU _ ids();//cpuid相关性
setup _ per _ CPU _ areas();//请求每个cpu变量的空间(包括gdt)
//smp中用于启动的cpu。
SMP _ prepare _ boot _ CPU();/*特定于arch的引导cpu挂钩*/
//建立系统内存页面链表。
build_all_zonelists(空);
//内存页面相关初始化
page _ alloc _ init();
printk(KERN _ NOTICE & quot;内核命令行:% s \ n & quot,boot _ command _ line);
//命令行引导命令行
parse _ early _ param();
//解析参数
parse _ args(& quot;启动内核& quot,static_command_line,__start___param,
__stop___param - __start___param,
-1,-1,& amp未知_ boot option);
//
jump _ label _ init();
/*
*这些使用大量的bootmem分配,并且必须在
* kmem_cache_init()
*与内存初始化相关
*/
setup _ log _ buf(0);
PID hash _ init();
VFS _ cache _ init _ early();
sort _ main _ extable();
trap_init()。
mm _ init();
/*
*在启动任何中断之前设置调度程序(例如
*定时器中断)。完整的拓扑设置发生在smp_init()
*时间——但与此同时,我们仍然有一个正常运行的调度程序。
*调度初始化
*/
sched _ init();
/*
*禁用抢占-早期启动调度是极其
*脆弱直到我们第一次cpu_idle()。
*抢占被禁用
*/
preempt _ disable();
如果(!irqs_disabled()) {
printk(KERN _ WARNING & quot;start_kernel():错误:中断被& quot
"很早就启用了,正在修复它\ n & quot);
local _ IRQ _ disable();
}
IDR _ init _ cache();//idr
perf_event_init()。//性能事件
rcu _ init();//读取-复制-更新机制
radix_tree_init()。//基数树机制
/* init init _ ISA _ irqs()*/之前的一些链接
early _ IRQ _ init();//中断请求
init _ IRQ();//中断请求
prio _ tree _ init();//先找到树
init_timers()。//时钟
HR timers _ init();//高分辨率内核定时器高精度内核时钟
softirq _ init();//软中断
time keying _ init();//时间相关性
time _ init();//时间
profile _ init();//分配内核性能统计节省的内存
call_function_init()。//在//smp中每个cpu的call_single_queue初始化。
如果(!irqs_disabled())
printk(KERN _ CRIT & quot;start_kernel():错误:中断被& quot
"提前启用\ n & quot);
early _ boot _ irqs _ disabled = false;//中断请求开启
local _ IRQ _ enable();//本地断开连接
kmem _ cache _ init _ late();//kmem后期初始化
/*
*黑客警报!这太早了。我们& # 39;重新启用控制台之前
*我们& # 39;我已经完成了PCI设置等,console_init()必须知道
*这个。但我们确实希望尽早输出,以防出现问题。
*/
console _ init();//初始化系统控制台结构
如果(慌_后)
panic(panic_later,panic _ param);
//锁定依赖信息
lock dep _ info();
/*
*需要在IRQ启用时运行,因为它希望
*自测[硬/软]-IRQ开/关锁定反转错误
*也是:
*/
locking _ self test();
#ifdef配置_ BLK _开发_初始化
if(initrd _ start & amp;& amp!initrd_below_start_ok。& amp
page _ to _ pfn(virt _ to _ page((void *)initrd _ start))& lt;min_low_pfn) {
printk(KERN _ CRIT & quot;initrd被覆盖(0x % 08lx & lt0x % 08lx)-& quot;
"关闭它。\ n & quot,
page _ to _ pfn(virt _ to _ page((void *)initrd _ start)),
min _ low _ pfn);
initrd _ start = 0;
}
#endif
page _ cgroup _ init();//控制组初始化
debug _ objects _ mem _ init();//对象调试
kmem leak _ init();//检测内核内存泄漏的功能
setup _ per _ CPU _ pageset();//申请并初始化每cpu页面的设置。
numa _ policy _ init();//numa相关性
if(延迟时间初始化)
late _ time _ init();
//初始化每个CPU的sched _ clock _ data = ktime _ now。
sched _ clock _ init();
calibrate _ delay();//计算cpuMIPS /s的百万条指令
PID map _ init();//pid进程id表初始化
anon _ VMA _ init();//虚拟地址
#ifdef CONFIG_X86
if (efi_enabled)//efi bois
EFI _ enter _ virtual _ mode();
#endif
thread _ info _ cache _ init();//申请线程信息的内存。
cred _ init();//凭据是活动分配的。
//根据物理内存大小计算可以创建的线程数量。
fork _ init(total ram _ pages);
proc _ cache _ init();//处理内存初始化
buffer_init()。//页面缓存
key _ init();//红黑树内存,存储键
security _ init();//安全相关
dbg _ late _ init();//调试相关
VFS _ caches _ init(total ram _ pages);//虚拟文件系统初始化
signals _ init();//sigqueue适用于内存和信号系统。
/* rootfs填充可能需要页写回*/
page _ write back _ init();//页面写回
#ifdef配置_过程_文件系统
proc _ root _ init();//proc文件系统初始化
#endif
cgroup _ init();//cgroup相关性
CPU set _ init();//cpuset相关性
task stats _ init _ early();//进程计数器
delay acct _ init();//流程延迟审核
check _ bugs();//系统bug相关测试
//acpi总线
acpi _ early _ init();LAPIC和SMP init之前*/
SFI _ init _ late();//简单固件接口
//函数跟踪初始化,一个调试工具
ftrace _ init();
/*完成剩余的非_ _ init & # 39艾德,我们& # 39;你现在还活着*/
rest _ init();
}
/*调用链接到内核的所有构造函数。*/
静态void _ init _ doctors(void)
{
#ifdef配置_构造函数
ctor _ fn _ t * fn =(ctor _ fn _ t *)_ _ ctors _ start;
for(;fn & lt(ctor _ fn _ t *)_ _ ctors _ end;fn++)
(* fn)();
#endif
}
bool initcall _ debug
core_param(initcall_debug,initcall_debug,bool,0644);
静态char msgbuf[64];
静态int _ _ init _ or _ module do _ one _ init call _ debug(init call _ t fn)
{
ktime_t calltime,delta,rettime
无符号long长持续时间;
int ret
printk(KERN _ DEBUG & quot;正在呼叫% pF @ % i \ n & quot,fn,task_pid_nr(当前));
call time = ktime _ get();
ret = fn();
rettime = ktime _ get();
delta = ktime_sub(rettime,call time);
duration =(unsigned long long)ktime _ to _ ns(delta)>& gt10;
printk(KERN _ DEBUG & quot;initcall %pF在%lld次使用后返回了%d次\ n & quot,fn,
ret,持续时间);
返回ret
}
int _ _ init _ or _ module do _ one _ init call(init call _ t fn)
{
int count = preempt _ count();
int ret
if (initcall_debug)
ret = do _ one _ init call _ debug(fn);
其他
ret = fn();
msgbuf[0]= 0;
如果(ret & amp& ampret!=-ENODEV & amp;& ampinitcall_debug)
sprintf(msgbuf,& quot错误代码% d & quot,ret);
if (preempt_count()!=计数){
strlcat(msgbuf,& quot先占失衡& quot,sizeof(msgbuf));
preempt _ count()= count;
}
if (irqs_disabled()) {
strlcat(msgbuf,& quot禁用的中断& quot,sizeof(msgbuf));
local _ IRQ _ enable();
}
if (msgbuf[0]) {
printk(& quot;initcall %pF返回了% s \ n & quot、fn、msgbuf);
}
返回ret
}
extern init call _ t _ _ init call _ start[];
extern init call _ t _ _ init call 0 _ start[];
extern init call _ t _ _ init call 1 _ start[];
extern init call _ t _ _ init call 2 _ start[];
extern init call _ t _ _ init call 3 _ start[];
extern init call _ t _ _ init call 4 _ start[];
extern init call _ t _ _ init call 5 _ start[];
extern init call _ t _ _ init call 6 _ start[];
extern init call _ t _ _ init call 7 _ start[];
extern init call _ t _ _ init call _ end[];
静态init call _ t * init call _ levels[]_ _ init data = {
__initcall0_start
__initcall1_start
__initcall2_start
__initcall3_start
__initcall4_start
__initcall5_start
__initcall6_start
__initcall7_start
__initcall_end
};
static char * init call _ level _ names[]_ _ initdata = {
"早期参数& quot,
"核心参数& quot,
"邮政编码参数& quot,
"拱形参数& quot,
"子系统参数& quot,
"fs参数",
"设备参数& quot,
"后期参数& quot,
};
静态void _ _ init do _ init call _ level(int level)
{
extern const struct kernel _ param _ _ start _ _ _ param[],_ _ stop _ _ _ param[];
initcall _ t * fn
strcpy(static_command_line,saved _ command _ line);
parse _ args(init call _ level _ names[level],
static_command_line,_ _ start _ _ _ param,
__stop___param - __start___param,
水平,水平,
repair _ env _ string);
for(fn = init call _ levels[level];fn & ltinit call _ levels[level+1];fn++)
do _ one _ init call(* fn);
}
静态void __init do_initcalls(void)
{
int级别;
for(级别= 0;级别& ltARRAY _ SIZE(init call _ levels)-1;level++)
do_initcall_level(级别);
}
/*
*好了,机器现在已经初始化。没有一个设备
*已被触摸,但CPU子系统已启动
*运行,内存和进程管理工作正常。
*
*现在我们终于可以开始做一些真正的工作了..
*/
静态void __init do_basic_setup(void)
{
CPU set _ init _ SMP();///smp cpuset相关性
user mode helper _ init();//khelper单线程工作队列
shmem _ init();//sheme机制
driver _ init();//驱动各个子系统。
init _ IRQ _ proc();//在//proc中创建irq目录。
do _ ctors();//内核中的所有构造函数。科茨科。
usermodehelper _ enable();
//编译到内核中的所有驱动模块的初始化函数
do _ init calls();
}
静态void _ _ init do _ pre _ SMP _ init calls(void)
{
initcall _ t * fn
for(fn = _ _ init call _ start;fn & lt_ _ initcall0 _ startfn++)
do _ one _ init call(* fn);
}
静态void run _ init _ process(const char * init _ filename)
{
argv _ init[0]= init _文件名;
kernel_execve(init_filename,argv_init,envp _ init);
}
/*这是非__init函数。强制它脱机,否则gcc
*将其内联到init()中,并成为init.text部分的一部分
*这是一个非init函数,用于防止gcc将其内联到Init()并成为Init.text段的一部分。
*/
静态noinline int init_post(void)
{
/*需要在释放内存之前完成所有async __init代码
*在释放init内存之前,必须完成所有__init代码的执行。
*/
async _ synchronize _ full();
free _ init mem();//释放init中的内存。*细分市场。
//修改页表,确保只读数据段是只读的。
mark _ rodata _ ro();
//系统运行状态标志
system _ state = SYSTEM _ RUNNING
//numa默认策略
numa_default_policy()。
//不能因为当前进程是init就将其终止。
当前->;信号->;flags | = SIGNAL _ UNKILLABLE
//如果ramdisk_execute_command变量指定了init程序,就执行它。
if (ramdisk_execute_command) {
run _ init _ process(ramdisk _ execute _ command);
printk(KERN _ WARNING & quot;无法执行% s \ n & quot,
ramdisk _ execute _ command);
}
/*
*我们尝试每一种方法,直到有一种成功。
*
*如果需要,可以使用Bourne shell代替init
*试图恢复一台真正损坏的机器。
*另一个程序,看能不能执行。如果没有,执行下面四个中的一个。
*/
if (execute_command) {
run_init_process(执行命令);
printk(KERN _ WARNING & quot;无法执行%s。正在尝试& quot
"默认...\ n & quot,execute _ command);
}
运行初始化进程(& quot/sbin/init & quot;);
运行初始化进程(& quot/etc/init & quot;);
运行初始化进程(& quot/bin/init & quot;);
运行初始化进程(& quot/bin/sh & quot;);
//两个变量和四个init无法成功执行,报错。
恐慌(& quot找不到初始化。尝试将init= option传递给内核。"
"请参阅Linux Documentation/init.txt以获取指导。");
}
static int _ _ init kernel _ init(void *未使用)
{
/*
*等到kthreadd全部设置完毕。等待kthreadd启动。
*/
等待完成。kthreadd _ done);
/*现在调度程序已经完全设置好,可以进行阻塞分配了
*
*/
GFP _ allowed _ MASK = _ _ GFP _ BITS _ MASK;
/*
* init可以在任何节点上分配页面
*/
set _ MEMS _ allowed(node _ States[N _ HIGH _ MEMORY]);
/*
* init可以在任何cpu上运行。
*/
set _ CPU _ allowed _ ptr(current,CPU _ all _ mask);
//cad_pid是接收Ctrl-alt-del操作的INT信号的进程id,设置为init的pid。
//说明init可以接受这三个键。
cad_pid = task_pid(当前);
//smp系统准备并激活所有CPU。
SMP _ prepare _ CPU(setup _ max _ CPU);
do _ pre _ SMP _ init calls();
lock up _ detector _ init();
SMP _ init();
sched _ init _ SMP();
//初始化设备驱动程序和内核模块
do _ basic _ setup();
/*打开rootfs上的/dev/console,这应该不会失败
*打开/dev/控制台设备。
*/
if(sys _ open((const char _ _ user *)& quot;/dev/控制台& quot,O_RDWR,0)& lt;0)
printk(KERN _ WARNING & quot;警告:无法打开初始控制台。\ n & quot);
/*
*复制标准输入0两次,一次是标准输入1,一次是标准误差2。
*/
(void)sys _ dup(0);
(void)sys _ dup(0);
/*
*检查是否有早期用户空间初始化。如果是,让它做所有的
*工作
*是否有早期用户空间初始化进程,如果有,让它执行?
*/
如果(!内存磁盘执行命令)
ramdisk _ execute _ command = & quot/init & quot;;
if(sys _ access((const char _ _ user *)ramdisk _ execute _ command,0)!= 0) {
ramdisk _ execute _ command = NULL
prepare_namespace()。
}
/*
*好了,我们已经完成了初始启动,并且
*我们& # 39;我们基本上已经开始运行了。扔掉那些
* initmem段并启动用户模式的东西..
*/
//启动用户空间的init进程。
init _ post();
返回0;
}
评论前必须登录!
注册