嵌入式 hi3518c内核start_kernel函数小议

 

嵌入式 hi3518c内核start_kernel函数小议

分类: 嵌入式   49人阅读  评论(0)  收藏  举报

我们先来看源码,有代码才有说服力哦:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:12px;">  
  2. 1.asmlinkage void __init start_kernel(void)  
  3.   
  4. 2. {  
  5.   
  6. 3.     char * command_line;  
  7.   
  8. 4.     extern const struct kernel_param __start___param[], __stop___param[];  
  9.   
  10. 5.   
  11.   
  12. 6.     smp_setup_processor_id(); //确定SMP系统中每个CPU的id  
  13.   
  14. 7.   
  15.   
  16. 8.     /* 
  17.  
  18. 9.      * Need to run as early as possible, to initialize the 
  19.  
  20. 10.      * lockdep hash: 
  21.  
  22. 11.      */  
  23.   
  24. 12.     lockdep_init(); //初始化互斥锁的dependency。  
  25.   
  26. 13.     debug_objects_early_init(); //初始化debug kernel相关  
  27.   
  28. 14.   
  29.   
  30. 15.     /* 
  31.  
  32. 16.      * Set up the the initial canary ASAP: 
  33.  
  34. 17.      */  
  35.   
  36. 18.     boot_init_stack_canary(); //stack_canary的是带防止栈溢出攻击保护的堆栈。  
  37.   
  38. 19.   
  39.   
  40. 20.     cgroup_init_early(); //cgroup是什么??有待查找  
  41.   
  42. 21.   
  43.   
  44. 22.     local_irq_disable(); //这个太直白了。  
  45.   
  46. 23.     early_boot_irqs_off(); //这个也很直白。  
  47.   
  48. 24.   
  49.   
  50. 25. /* 
  51.  
  52. 26.  * Interrupts are still disabled. Do necessary setups, then 
  53.  
  54. 27.  * enable them 
  55.  
  56. 28.  */  
  57.   
  58. 29.     tick_init(); //初始化time ticket,时钟  
  59.   
  60. 30.     boot_cpu_init(); //用以启动的CPU进行初始化。也就是初始化CPU0  
  61.   
  62. 31.     page_address_init();//初始化页面  
  63.   
  64. 32.     printk(KERN_NOTICE "%s", linux_banner);  
  65.   
  66. 33.     setup_arch(&command_line); //CPU架构相关的初始化  
  67.   
  68. 34.     mm_init_owner(&init_mm, &init_task); //初始化内存管理  
  69.   
  70. 35.     setup_command_line(command_line); //处理启动命令行  
  71.   
  72. 36.     setup_nr_cpu_ids(); //nr_cpu_id是什么?  
  73.   
  74. 37.     setup_per_cpu_areas(); //为每个CPU开辟一块区域?  
  75.   
  76. 38.     smp_prepare_boot_cpu();//准备boot_cpu.   /* arch-specific boot-cpu hooks */   
  77.   
  78. 39.   
  79.   
  80. 40.     build_all_zonelists(NULL); //建立什么样的zone??  
  81.   
  82. 41.     page_alloc_init(); //初始化page allocation相关结构  
  83.   
  84. 42.   
  85.   
  86. 43.     printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);  
  87.   
  88. 44.     parse_early_param();   
  89.   
  90. 45.     parse_args("Booting kernel", static_command_line, __start___param,  
  91.   
  92. 46.          __stop___param - __start___param,  
  93.   
  94. 47.          &unknown_bootoption);//解析启动参数  
  95.   
  96. 48.     /* 
  97.  
  98. 49.      * These use large bootmem allocations and must precede 
  99.  
  100. 50.      * kmem_cache_init() 
  101.  
  102. 51.      */  
  103.   
  104. 52.     pidhash_init();//初始化process ID hash表  
  105.   
  106. 53.     vfs_caches_init_early(); //文件系统caches预初始化  
  107.   
  108. 54.     sort_main_extable(); //初始化exception table  
  109.   
  110. 55.     trap_init(); //初始化trap,用以处理错误执行代码  
  111.   
  112. 56.     mm_init(); //初始化内存管理  
  113.   
  114. 57.     /* 
  115.  
  116. 58.      * Set up the scheduler prior starting any interrupts (such as the 
  117.  
  118. 59.      * timer interrupt). Full topology setup happens at smp_init() 
  119.  
  120. 60.      * time - but meanwhile we still have a functioning scheduler. 
  121.  
  122. 61.      */  
  123.   
  124. 62.     sched_init(); //进程调度初始化  
  125.   
  126. 63.     /* 
  127.  
  128. 64.      * Disable preemption - early bootup scheduling is extremely 
  129.  
  130. 65.      * fragile until we cpu_idle() for the first time. 
  131.  
  132. 66.      */  
  133.   
  134. 67.     preempt_disable(); //这个是什么东东?  
  135.   
  136. 68.     if (!irqs_disabled()) {  
  137.   
  138. 69.         printk(KERN_WARNING "start_kernel(): bug: interrupts were "  
  139.   
  140. 70.                 "enabled *very* early, fixing it\n");  
  141.   
  142. 71.         local_irq_disable();  
  143.   
  144. 72.     }  
  145.   
  146. 73.     rcu_init(); //Read_Copy_Update机制初始  
  147.   
  148. 74.     radix_tree_init(); //什么是radlx_tree  
  149.   
  150. 75.     /* init some links before init_ISA_irqs() */  
  151.   
  152. 76.     early_irq_init();  
  153.   
  154. 77.     init_IRQ(); //初始化中断  
  155.   
  156. 78.     prio_tree_init(); //这是啥?以后要弄懂  
  157.   
  158. 79.     init_timers(); //初始化时钟  
  159.   
  160. 80.     hrtimers_init();//初始化高精时钟  
  161.   
  162. 81.     softirq_init();//初始化软中断  
  163.   
  164. 82.     timekeeping_init();//初始化时钟源  
  165.   
  166. 83.     time_init();//初始化时间例程  
  167.   
  168. 84.     profile_init(); //Profile?这是什么profile?  
  169.   
  170. 85.     if (!irqs_disabled())  
  171.   
  172. 86.         printk(KERN_CRIT "start_kernel(): bug: interrupts were "  
  173.   
  174. 87.                  "enabled early\n");  
  175.   
  176. 88.     early_boot_irqs_on();  
  177.   
  178. 89.     local_irq_enable();  
  179.   
  180. 90.   
  181.   
  182. 91.     /* Interrupts are enabled now so all GFP allocations are safe. */  
  183.   
  184. 92.     gfp_allowed_mask = __GFP_BITS_MASK;  
  185.   
  186. 93.   
  187.   
  188. 94.     kmem_cache_init_late();//初始化CPU Cache  
  189.   
  190. 95.   
  191.   
  192. 96.     /* 
  193.  
  194. 97.      * HACK ALERT! This is early. We're enabling the console before 
  195.  
  196. 98.      * we've done PCI setups etc, and console_init() must be aware of 
  197.  
  198. 99.      * this. But we do want output early, in case something goes wrong. 
  199.  
  200. 100.      */  
  201.   
  202. 101.     console_init(); //初始化console  
  203.   
  204. 102.     if (panic_later)  
  205.   
  206. 103.         panic(panic_later, panic_param);  
  207.   
  208. 104.   
  209.   
  210. 105.     lockdep_info();  
  211.   
  212. 106.   
  213.   
  214. 107.     /* 
  215.  
  216. 108.      * Need to run this when irqs are enabled, because it wants 
  217.  
  218. 109.      * to self-test [hard/soft]-irqs on/off lock inversion bugs 
  219.  
  220. 110.      * too: 
  221.  
  222. 111.      */  
  223.   
  224. 112.     locking_selftest(); //自测试锁  
  225.   
  226. 113.   
  227.   
  228. 114. #ifdef CONFIG_BLK_DEV_INITRD  
  229.   
  230. 115.     if (initrd_start && !initrd_below_start_ok &&  
  231.   
  232. 116.      page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {  
  233.   
  234. 117.         printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "  
  235.   
  236. 118.          "disabling it.\n",  
  237.   
  238. 119.          page_to_pfn(virt_to_page((void *)initrd_start)),  
  239.   
  240. 120.          min_low_pfn);  
  241.   
  242. 121.         initrd_start = 0;  
  243.   
  244. 122.     }  
  245.   
  246. 123. #endif  
  247.   
  248. 124.     page_cgroup_init(); //页面初始  
  249.   
  250. 125.     enable_debug_pagealloc(); //页面分配debug启用  
  251.   
  252. 126.     kmemleak_init(); //memory leak 侦测初始化  
  253.   
  254. 127.     debug_objects_mem_init(); //debug object是什么?  
  255.   
  256. 128.     idr_init_cache(); //idr是什么?   
  257.   
  258. 129.     setup_per_cpu_pageset(); //设置每个CPU的页面集合  
  259.   
  260. 130.     numa_policy_init();// NUMA (Non Uniform Memory Access) policy   
  261. 131.     if (late_time_init)  
  262.   
  263. 132.         late_time_init();  
  264.   
  265. 133.     sched_clock_init();//初始化调度时钟  
  266.   
  267. 134.     calibrate_delay(); //协同不同CPU的时钟  
  268. 135.     pidmap_init();//pid是process id还是processor id?  
  269.   
  270. 136.     anon_vma_init();//anonymous page?什么意思?  
  271.   
  272. 137. #ifdef CONFIG_X86  
  273.   
  274. 138.     if (efi_enabled)  
  275.   
  276. 139.         efi_enter_virtual_mode();  
  277.   
  278. 140. #endif  
  279.   
  280. 141.     thread_info_cache_init(); //初始化thread info  
  281.   
  282. 142.     cred_init(); //credential  
  283.   
  284. 143.     fork_init(totalram_pages); //初始化fork  
  285.   
  286. 144.     proc_caches_init(); //初始化/proc的cache?  
  287.   
  288. 145.     buffer_init(); // buffer  
  289.   
  290. 146.     key_init(); //key  
  291.   
  292. 147.     security_init();//security  
  293.   
  294. 148.     dbg_late_init();//debug  
  295.   
  296. 149.     vfs_caches_init(totalram_pages);//文件系统cache初始化  
  297.   
  298. 150.     signals_init();//signal  
  299.   
  300. 151.     /* rootfs populating might need page-writeback */  
  301.   
  302. 152.     page_writeback_init();page_writeback  
  303.   
  304. 153. #ifdef CONFIG_PROC_FS  
  305.   
  306. 154.     proc_root_init();  
  307.   
  308. 155. #endif  
  309.   
  310. 156.     cgroup_init(); //cgroup?  
  311.   
  312. 157.     cpuset_init(); //cpuset  
  313.   
  314. 158.     taskstats_init_early(); //task  
  315.   
  316. 159.     delayacct_init();  
  317.   
  318. 160.   
  319.   
  320. 161.     check_bugs(); //检查什么bug?  
  321.   
  322. 162.   
  323.   
  324. 163.     acpi_early_init();//acpi /* before LAPIC and SMP init */   
  325.   
  326. 164.     sfi_init_late(); //simple firmware interface  
  327.   
  328. 165.   
  329.   
  330. 166.     ftrace_init();  
  331.   
  332. 167.   
  333.   
  334. 168.     /* Do the rest non-__init'ed, we're now alive */  
  335.   
  336. 169.     rest_init();  
  337.   
  338. 170. }  
  339. </span>  


 

下面进行一下重要函数的解析:

start_kernel()函数位于init/main.c中,是引导过程中最重要的一个函数,就像它的名字一样,它初始化了内核所有的功能。
   1,调用lock_kernel(),防止内核被意外抢断,定义在lib/kernel_lock.c中。在SMP或者抢断式调度环境中,内核可以被抢断。内核初始化时,功能还不完善,为防止此种情况发生,使用称为Big Kernel Lock的spinlock。spinlock是一种忙等待锁,如果等待周期不是很长,它比信号有效,因为信号会造成进程调度。Big Kernel Lock只在内核初始化时使用,当初始化结束后,该锁被释放。
   2,page_address_init()函数初始化页管理,创建了页管理所需的数据结构,定义在mm/highmem.c中。
   3,输出内核版本信息,执行了两个内核输出语句printk(KERN_NOTICE)和printk(linux_banner)。因为此时还没有初始化控制台,所以这些信息不能输出到屏幕上或者输出到串口上,而是输出到一个buffer中。printk()函数定义在kernel/printk.c 中,KERN_NOTICE宏定义在include/linux/kernel.h中,值为"<5>"。linux_banner定义在 init/version.c中,在我的实验环境中是这样的一个字符串:Linux version 2.6.28 (zctan@dbgkrnl) (gcc version 4.3.0 20080428 (Red Hat 4.3.0-8) (GCC) ) #1 SMP Sun Feb 8 20:56:17 CST 2009。
   4,setup_arch(),位于arch/x86/kernel/setup.c,初始化了许多体系结构相关的子系统。
   5,setup_per_cpu_area(),定义在arch/x86/kernel/setup_percpu.c中,如果是SMP环境,则为每个CPU创建数据结构,分配初始工作内存。
   6,smp_prepare_boot_cpu(),定义在include/asm-x86/smp.h。如果是SMP环境,则设置boot CPU的一些数据。在引导过程中使用的CPU称为boot CPU。
   7,sched_init(),定义在kernel/sched.c。初始化每个CPU的运行队列和超时队列。Linux使用多优先级队列的调度方法,就绪进程位于运行队列中。
   8,build_all_zonelists(),定义在mm/page_alloc.c中,建立内存区域链表。Linux将所有物理内存分为三个区,ZONE_DMA, ZONE_NORMAM, ZONE_HIGHMEM。
   9,trap_init(),定义在arch/x86/kernel/traps_32.c中,初始化IDT, 如除0错,缺页中断等。
   10,rcu_init(),定义在kernel/rcupdate.c中,初始化Read-Copy-Update子系统。当使用spinlock会造成效率低下时,RCU被用来实现临界区的互斥。
   11,init_IRQ(),定义在arch/x86/kernel/paravirt.c中,初始化中断控制器。
   12,pidhash_init(),定义在kernel/pid.c中,Linux的进程描述符称为PID, 使用名称空间以及hash表来管理。
   13,init_timers(),定义在kernel/timer.c中,初始化定时器。
   14,softirq_init(),定义在kernel/softirq.c中,初始化中断子系统,如softirq, tasklet。
   15,time_init(),定义在arch/x86/kernel/time_32.c中,初始化系统时间。
   16,profile_init(),定义在kernel/profile.c中,为profiling data分配存储空间。Profiling data这个术语描述在程序运行过程中采集到的一些数据,用于性能的分析。
   17,local_irq_enable(),定义在include/linux/irqflags.h中,开启引导CPU的中断。
   18,console_init(),定义在drivers/char/tty_io.c中,初始化控制台,可以是显示器也可以是串口。此时屏幕上才会有输出,前面printk输出到buffer中的内容会在这里全部输出。
   19,initrd检测。如果定义了Init Ram Disk,则检测其是否有效。
   20,mem_init(),定义在arch/x86/mm/init_32.c,检测所有可用物理页。
   21,pgtable_cache_init(),定义在include/asm-x86/pgtable_32.h,在slab存储管理子系统中创建页目录页表的cache。
   22,fork_init(),定义在kernel/fork.c中,初始化多进程环境。此时,执行start_kernel的进程就是所谓的进程0。
   23,buffer_init(),定义在fs/buffer.c中,初始化文件系统的缓冲区。
   24,vfs_cache_init(),定义在fs/dcache.c中,创建虚拟文件系统的Slab Cache。
   25,radix_tree_init(),定义在lib/radix-tree.c。Linux使用radix树来管理位于文件系统缓冲区中的磁盘块,radix树是trie树的一种。
   26,signals_init(),定义在kernel/signal.c中,初始化信号队列。
   27,page_writeback_init(),定义在mm/page-writeback.c中,初始化将脏页页同步到磁盘上的控制信息。
   28,proc_root_init(),定义在fs/proc/root.c, 初始化proc文件系统
   29,rest_init(),定义在init/main.c中,创建init内核线程(也就是进程1)。init进程创建成功后,进程0释放Big Kernel Lock,重新调度(因为现在只有两个进程,所以调度的是init进程)。进程0,就变成了idle进程,只负责调度。
   注:start_kernel函数涉及到很多内容和硬件知识,比如SMP等,有很多是我不知道的,所以只能简要的从功能上说明一下,有些可能理解错了,也会略过一些函数,请见谅。
  六,init进程
   init进程执行定义在init/main.c中的kernel_init()函数,完成余下的初始化工作。
   1,lock_kernel(),加上Big Kernel Lock。
   2,初始化SMP环境。
   3,do_basic_setup()。调用driver_init(),加载设备驱动程序。执行do_initcalls(),调用内建模块的初始化函数,比如kgdb。
   4,init_post()函数会打开/dev/console做为标准输入文件,并复制出标准输出和标准错误输出。最后,按下列顺序偿试执行init程序,位于ramdisk的/init,以及磁盘上的/sbin/init, /etc/init, /bin/init和/bin/sh, 只要有一个能执行就可以。init进程会使用类exec()去调用其它进程,因而不会返回。

CPU初始化
smp_setup_processor_id()
boot_cpu_init()
setup_arch(&command_line);
setup_nr_cpu_ids()
setup_per_cpu_areas()
smp_prepare_boot_cpu()
setup_per_cpu_pageset();
calibrate_delay();
cpuset_init();
内存管理初始化
boot_init_stack_canary()
page_address_init();
mm_init_owner();
page_alloc_init();
mm_init();
rcu_init();
kmem_cache_init_late();
page_cgroup_init();
kmemleak_init();
numa_policy_init();
anon_vma_init();
page_writeback_init();
进程管理
pidhash_init();
sched_init();
sched_clock_init()
pidmap_init();
fork_init(totalram_pages);
taskstats_init_early();
文件系统
vfs_caches_init_early();
thread_info_cache_init();
vfs_caches_init(totalram_pages);
中断
early_irq_init();
init_IRQ();
softirq_init();
同步互斥
lockdep_init();
lockdep_info();
locking_selftest();
时钟
tick_init();
init_timers();
hrtimers_init();
timekeeping_init();
time_init();
调试
debug_objects_early_init();
console_init();
enable_debug_pagealloc();
debug_objects_mem_init();
dbg_late_init();
其他
sort_main_extable();
trap_init();
efi_enter_virtual_mode();
cred_init();
proc_caches_init();
buffer_init();
key_init();
security_init();
signals_init();
proc_root_init();
delayacct_init();
check_bugs();
acpi_early_init();
sfi_init_late();
未知
cgroup_init_early();
build_all_zonelists(NULL);
preempt_disable();
radix_tree_init();
prio_tree_init();
profile_init();
idr_init_cache();
cgroup_init();
ftrace_init();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值