Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja

转自:http://blog.chinaunix.net/uid-25909619-id-4938396.html

在基本分析完内核启动流程的之后,还有一个比较重要的初始化函数没有分析,那就是do_basic_setup。在内核init线程中调用了do_basic_setup,这个函数也做了很多内核和驱动的初始化工作,详解如下:

  1. /*
  2. * 好了, 设备现在已经初始化完成。 但是还没有一个设备被初始化过,
  3. * 但是 CPU 的子系统已经启动并运行,
  4. * 且内存和处理器管理系统已经在工作了。
  5. *
  6. * 现在我们终于可以开始做一些实际的工作了..
  7. */
  8. static void __init do_basic_setup(void)
  9. {
  10. cpuset_init_smp();

    点击(此处)折叠或打开

    1. 针对SMP系统,初始化内核control group的cpuset子系统。如果非SMP,此函数为空。
    2. cpuset是在用户空间中操作cgroup文件系统来执行进程与cpu和进程与内存结点之间的绑定。
    3. 本函数将cpus_allowed和mems_allwed更新为在线的cpu和在线的内存结点,并为内存热插拨注册了钩子函数,最后创建一个单线程工作队列cpuset。
  11. usermodehelper_init();

    点击(此处)折叠或打开

    1. 创建一个单线程工作队列khelper。运行的系统中只有一个,主要作用是指定用户空间的程序路径和环境变量, 最终运行指定的user space的程序,属于关键线程,不能关闭。
  12. init_tmpfs();

    点击(此处)折叠或打开

    1. 初始化内核tmpfs文件系统
  13.     driver_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的各子系统,可见的现象是在/sys中出现的目录和文件
  14. init_irq_proc();

    点击(此处)折叠或打开

    1. 在proc文件系统中创建irq目录,并在其中初始化系统中所有中断对应的目录。
  15. do_ctors();

    点击(此处)折叠或打开

    1. 调用链接到内核中的所有构造函数,也就是链接进.ctors段中的所有函数。
    2. 在Linux-2.6.31开始内核启动增加了对构造函数的支持。
    3. git提交:

      点击(此处)折叠或打开

      1. commit b99b87f70c7785ab1e253c6220f4b0b57ce3a7f7
      2. Author: Peter Oberparleiter<[email protected]>
      3. Date: Wed Jun 17 16:28:03 2009 -0700
      4. kernel: constructor support

      内核:构造函数支持

      1. Call constructors (gcc-generated initcall-like functions) during kernel
      2. start and module load. Constructors are e.g. used for gcov data
      3. initialization.
      4. 在内核启动和模块挂载时,调用构造函数(gcc生成的类初始化函数)。构造函数就是
      5. 比如用于初始化gcov数据的函数
      6. Disable constructor support for usermode Linux to prevent conflicts with
      7. host glibc.
      8. 对于Linux的用户模式禁用构造函数支持,以避免和glibc冲突。
      9. Signed-off-by: Peter Oberparleiter<[email protected]>
      10. Acked-by: Rusty Russell<[email protected]>
      11. Acked-by: WANG Cong<[email protected]>
      12. Cc: Sam Ravnborg<[email protected]>
      13. Cc: Jeff Dike<[email protected]>
      14. Cc: Andi Kleen<[email protected]>
      15. Cc: Huang Ying<[email protected]>
      16. Cc: Li Wei<[email protected]>
      17. Cc: Michael Ellerman<[email protected]>
      18. Cc: Ingo Molnar<[email protected]>
      19. Cc: Heiko Carstens<[email protected]>
      20. Cc: Martin Schwidefsky<[email protected]>
      21. Cc: Al Viro<[email protected]>
      22. Signed-off-by: Andrew Morton<[email protected]>
      23. Signed-off-by: Linus Torvalds<[email protected]>

      $ git tag --contains b99b87f7

      v2.6.31

      v2.6.31-rc1

      v2.6.31-rc2

      v2.6.31-rc3

      v2.6.31-rc4

      v2.6.31-rc5

      v2.6.31-rc6

      v2.6.31-rc7

      v2.6.31-rc8

      v2.6.31-rc9

      v2.6.32

      v2.6.32-rc1

      v2.6.32-rc2

      v2.6.32-rc3

      v2.6.32-rc4

      v2.6.32-rc5

      v2.6.32-rc6

      v2.6.32-rc7

      v2.6.32-rc8

  16.     do_initcalls();

    点击(此处)折叠或打开

    1. 调用所有编译内核的驱动模块中的初始化函数。
    2. 这里就是驱动程序员需要关心的步骤,其中按照各个内核模块初始化函数所自定义的启动级别(1~7),按顺序调用器初始化函数。
    3. 对于同一级别的初始化函数,安装编译是链接的顺序调用,也就是和内核Makefile的编写有关。

    在编写内核模块的时候需要知道这方面的知识,比如你编写的模块使用的是I2C的API,那你的模块的初始化函数的级别必须低于I2C子系统初始化函数的级别(也就是级别数(1~7)要大于I2C子系统)。如果编写的模块必须和依赖的模块在同一级,那就必须注意内核Makefile的修改了。

    这方面的知识会在有空的时候总结下,网上也有相关的文章。

  17. }

上面的函数调用了driver_init函数,作用是驱动模型子系统的初始化,对于内核驱动工程师来说比较重要,详解如下:

drivers/base/init.c:

  1. /**
  2. * driver_init - 初始化驱动模型.
  3. *
  4. * 调用驱动模型初始化函数来初始化它们的子系统。
  5. * 由早期的init/main.c中调用。
  6. */
  7. void __init driver_init(void)
  8. {
  9. /* 它们为核心部件 */
  10. devtmpfs_init();

    点击(此处)折叠或打开

    1. 初始化devtmpfs文件系统,驱动核心设备将在这个文件系统中添加它们的设备节点。
    2. 这个文件系统可以由内核在挂载根文件系统之后自动挂载到/dev下,也可以在文件系统的启动脚本中手动挂载。
  11. devices_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的部分子系统和kobject:
    2. devices
    3. dev
    4. dev/block
    5. dev/char
  12. buses_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的bus子系统
  13. classes_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的class子系统
  14. firmware_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的firmware子系统
  15. hypervisor_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的hypervisor子系统
  16. /* 这些也是核心部件, 但是必须
  17. * 在以上核心中的核心部件之后调用。
  18. */
  19. platform_bus_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的bus/platform子系统
  20. system_bus_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的devices/system子系统
  21. cpu_dev_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的devices/system/cpu子系统
  22. memory_dev_init();

    点击(此处)折叠或打开

    1. 初始化驱动模型中的devices/system/memory子系统
    2. 虽然从代码上看这样,但是我在实际的系统中并没有找到/sys/devices/system/memory这个目录
  23. }
时间: 2024-12-26 20:08:33

Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】的相关文章

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线

Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】

原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938390.html 在构架相关的汇编代码运行完之后,程序跳入了构架无关的内核C语言代码:init/main.c中的start_kernel函数,在这个函数中Linux内核开始真正进入初始化阶段, 下面我就顺这代码逐个函数的解释,但是这里并不会过于深入

Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938393.html 在分析start_kernel函数的时候,其中有构架相关的初始化函数setup_arch. 此函数根据构架而异,对于ARM构架的详细分析如下: void __init setup_arch(char **cmdlin

Linux tcp被动打开内核源码分析

[我是从2个角度来看,其实所谓2个角度,是发现我分析源码时,分析重复了,写了2个分析报告,所以现在都贴出来.] [如果你是想看看,了解一下内核tcp被动打开时如何实现的话,我觉得还是看看概念就可以了,因为即使看了源码,过一个个礼拜你就忘了,如果是你正在修改协议栈,为不知道流程而发愁,那么希望你能看看源码以及注释,希望你给你帮助.] 概念: tcp被动打开,前提是你listen,这个被动打开的前提.你listen过后,其实创建了一个监听套接字,专门负责监听,不会负责传输数据. 当第一个syn包到达

Linux内核源码分析方法

  一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都知道,想成为优秀的程序员,需要大量的实践和代码的编写.编程固然重要,但是往往只编程的人很容易把自己局限在自己的知识领域内.如果要扩展自己知识的广度,我们需要多接触其他人编写的代码,尤其是水平比我们更高的人编写的代码.通过这种途径,我们可以跳出自己知识圈的束缚,进入他人的知识圈,了解更多甚至我们一

ARMv8 Linux内核源码分析:__flush_dcache_all()

1.1 /* *  __flush_dcache_all() *  Flush the wholeD-cache. * Corrupted registers: x0-x7, x9-x11 */ ENTRY(__flush_dcache_all) //保证之前的访存指令的顺序 dsb sy //读cache level id register mrs x0, clidr_el1           // read clidr //取bits[26:24](Level of Coherency f

linux 内核源码分析 - 获取数组的大小

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 测试程序: #include<stdio.h> #include<stdlib.h> struct dev { int a; char b; float c; }; struct dev devs[]= { { 1,'a',7.0, }, { 1,'a',7.0, }, { 1,'a',7.0, }, }; int main() { printf("int is %d \

内核源码分析之进程地址空间(基于3.16-rc4)

所谓进程的地址空间,指的就是进程的虚拟地址空间.当创建一个进程时,内核会为该进程分配一个线性的地址空间(虚拟地址空间),有了虚拟地址空间后,内核就可以通过页表将进程的物理地址地址空间映射到其虚拟地址空间中,程序员所能看到的其实都是虚拟地址,物理地址对程序员而言是透明的.当程序运行时,MMU硬件机制会将程序中的虚拟地址转换成物理地址,然后在内存中找到指令和数据,来执行进程的代码.下面我们就来分析和进程的地址空间相关的各种数据结构和操作. 用到的数据结构: 1.内存描述符struct mm_stru

linux内存源码分析 - 内存压缩(同步关系)

本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 最近在看内存回收,内存回收在进行同步的一些情况非常复杂,然后就想,不会内存压缩的页面迁移过程中的同步关系也那么复杂吧,带着好奇心就把页面迁移的源码都大致看了一遍,还好,不复杂,也容易理解,这里我们就说说在页面迁移过程中是如何进行同步的.不过首先可能没看过的朋友需要先看看linux内存源码分析 - 内存压缩(一),因为会涉及里面的一些知识. 其实一句话可以概括页面迁移时是如何进行同步的,就是:我要开始对这