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内核开始真正进入初始化阶段,

下面我就顺这代码逐个函数的解释,但是这里并不会过于深入每个函数,因为这样就会只见树木,不见森林。分析代码首先要从构架上宏观地理解,然后再去考虑细节问题(这和小时候学语文要概括中心思想和段落大意是一个道理)。今后对于每个子系统的初始化,特别是内存子系统,有空都会分析一遍。

  1. asmlinkage void __init start_kernel(void)
  2. {
  3. char * command_line;
  4. extern const struct kernel_param __start___param[], __stop___param[];
  5. 点击(此处)折叠或打开
    1. 这里关键是这两个变量的地址是如何确定的。
    2. 这两个变量为地址指针,指向内核启动参数处理相关结构体段在内存中的位置(虚拟地址)。
    3. 这里是外部变量,定义的位置在arch/../../vmlinux.lds.S,而大多数平台是放到kernel\include\asm-generic\vmlinux.lds.h中,定义如下:
    4. 点击(此处)折叠或打开
      1. 362     /* 内建模块的参数处理段. */               \
      2. 363     __param : AT(ADDR(__param) - LOAD_OFFSET) {         \
      3. 364         VMLINUX_SYMBOL(__start___param) = .;            \
      4. 365         *(__param)                      \
      5. 366         VMLINUX_SYMBOL(__stop___param) = .;         \
      6. 367     }
    5. 对于ARM平台,似乎位于 kernel\include\asm-generic\vmlinux.lds.h
    6. 这个段中数据的数据结构:
    7. kernel_param结构体的定义是:

    点击(此处)折叠或打开

    1. 36 struct kernel_param_ops {
    2. 37      /* Returns 0, or -errno. arg is in kp->arg. */
    3. 38      int (*set)(const char *val, const struct kernel_param *kp);
    4. 39      /* Returns length written or -errno. Buffer is 4k (ie. be */
    5. 40      int (*get)(char *buffer, const struct kernel_param *kp);
    6. 41      /* Optional function to free kp->arg when module unloaded. */
    7. 42      void (*free)(void *arg);
    8. 43  };
    9. 44
    10. 45  /* Flag bits for kernel_param.flags */
    11. 46  #define KPARAM_ISBOOL 2
    12. 47
    13. 48 struct kernel_param {
    14. 49      const char *name;
    15. 50      const struct kernel_param_ops *ops;
    16. 51       u16 perm;
    17. 52      u16 flags;
    18. 53      union {
    19. 54          void *arg;
    20. 55          const struct kparam_string *str;
    21. 56          const struct kparam_array *arr;
    22. 57      };
    23. 58 };
    24. 59
    25. 60  /* Special one for strings we want to copy into */
    26. 61  struct kparam_string {
    27. 62      unsigned int maxlen;
    28. 63      char *string;
    29. 64  };
    30. 65
    31. 66  /* Special one for arrays */
    32. 67  struct kparam_array
    33. 68  {
    34. 69      unsigned int max;
    35. 70      unsigned int elemsize;
    36. 71      unsigned int *num;
    37. 72      const struct kernel_param_ops *ops;
    38. 73      void *elem;
    39. 74  };

  6. smp_setup_processor_id();
  7. 点击(此处)折叠或打开
    1. 这个函数是针对SMP处理器的,经查阅资料,其作用是获取当前CPU的的硬件ID。
    2. 如果不是多处理器构架,在其他文件中就不会定义这个函数,此时使用本文件定义的弱引用函数:
    3. void __init __weak smp_setup_processor_id(void)
    4. {
    5. }
  8. /*
  9.      * 必须尽早运行这个程序, 作用是初始化
  10.      * lockdep 模块的hash表:
  11. */
  12. lockdep_init();
  13. 点击(此处)折叠或打开
    1. lockdep是一个内核调试模块,用来检查内核互斥机制(尤其是自旋锁)潜在的死锁问题。
    2. 由于自旋锁以查询方式等待,不释放处理器,比一般互斥机制更容易死锁,故引入lockdep检查以下几种可能的死锁情况:
    • 同一个进程递归地加锁同一把锁;
    • 一把锁既在中断(或中断下半部)使能的情况下执行过加锁操作, 又在中断(或中断下半部)里执行过加锁操作。这样该锁有可能在锁定时由于中断发生又试图在同一处理器上加锁;
    • 加锁后导致依赖图产生成闭环,这是典型的死锁现象。
  14. debug_objects_early_init();
  15. 点击(此处)折叠或打开
    1. 在启动早期初始化hash buckets 和链接静态的 pool objects对象到 poll 列表. 在这个调用完成后 object tracker 已经开始完全运作了.
  16. /*
  17. *  初始化栈canary值:
  18. */
  19. boot_init_stack_canary();
  20. 点击(此处)折叠或打开
    1. canary值的是用于防止栈溢出攻击的堆栈的保护字 。
    2. 参考资料: GCC 中的编译器堆栈保护技术
  21. cgroup_init_early();
  22. 点击(此处)折叠或打开
    1. cgroup: 它的全称为control group.即一组进程的行为控制.
    2. 该函数主要是做数据结构和其中链表的初始化
    3. 参考资料: Linux cgroup机制分析之框架分析
  23. local_irq_disable();
  24. 点击(此处)折叠或打开
    1. 关闭系统总中断(底层调用汇编指令)
  25. early_boot_irqs_disabled = true;
  26. 点击(此处)折叠或打开
    1. 设置系统中断的关闭标志(bool全局变量)
  27. /*
  28. * 中断依然被禁用。做必要的设置后,
  29. * 再使能它
  30. */
  31. tick_init();
  32. 点击(此处)折叠或打开
    1. 初始化内核时钟系统
    2. -->clockevents_register_notifier(&tick_notifier)
    3. 往内核通知链中注册内核时钟时间的通知函数
    4. 参考资料:《Linux 时钟处理机制》  《Linux 时钟管理
  33. boot_cpu_init();
  34. 点击(此处)折叠或打开
    1. 激活当前CPU(在内核全局变量中将当前CPU的状态设为激活状态)
    2. 参考资料:《激活第一个CPU
  35. page_address_init();
  36. 点击(此处)折叠或打开
    1. 高端内存相关,未定义高端内存的话为空函数
  37.     printk(KERN_NOTICE "%s", linux_banner);
  38. 点击(此处)折叠或打开
    1. 打印内核版本信息,也就是平时我们在内核启动时在串口中看到的:
      1. Linux version 2.6.37+ ([email protected]) (gcc version 4.3.3 (Sourcery G++ Lite 2009q1-203) ) #40 Tue Mar 20 17:49:58 CST 2012
  39.     setup_arch(&command_line);
  40. 点击(此处)折叠或打开
    1. 内核构架相关初始化函数,可以说是非常重要的一个初始化步骤。其中包含了处理器相关参数的初始化、内核启动参数(tagged list)的获取和前期处理、内存子系统的早期的初始化(bootmem分配器)
    2. 对于ARM构架来说,这个函数位于:arch/arm/kernel/setup.c
    3. 以后会详细分析这个函数。
  41. mm_init_owner(&init_mm, &init_task);
  42. mm_init_cpumask(&init_mm);
  43. 点击(此处)折叠或打开
    1. 初始化代表内核本身内存使用的管理结构体init_mm。
    2. ps:每一个任务都有一个mm_struct结构以管理内存空间,init_mm是内核的mm_struct,其中:
    3. 设置成员变量* mmap指向自己,意味着内核只有一个内存管理结构;
    4. 设置* pgd=swapper_pg_dir,swapper_pg_dir是内核的页目录(在arm体系结构有16k, 所以init_mm定义了整个kernel的内存空间)。
    5. 这些内容涉及到内存管理子系统,以后再仔细分析。
  44. setup_command_line(command_line);
  45. 点击(此处)折叠或打开
    1. 对cmdline进行备份和保存
    2. /* 为处理的command line备份 (例如eg. 用于 /proc) */
    3. char *saved_command_line;
    4. /* 用于参数处理的command line */
    5. static char *static_command_line;
  46. setup_nr_cpu_ids();
  47. setup_per_cpu_areas();
  48. smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */
  49. 点击(此处)折叠或打开
    1. 针对SMP处理器的内存初始化函数,如果不是SMP系统则都为空函数。
    2. 他们的目的是给每个CPU分配内存,并拷贝.data.percpu段的数据。为系统中的每个CPU的per_cpu变量申请空间并为boot CPU设置一些数据。
    3. 在SMP系统中,在引导过程中使用的CPU称为boot CPU
  50. build_all_zonelists(NULL);
  51. page_alloc_init();
  52. 点击(此处)折叠或打开
    1. 设置内存管理相关的node(节点,每个CPU一个内存节点)和其中的zone(内存域,包含于节点中,如)数据结构,以完成内存管理子系统的初始化,并设置bootmem分配器。
    2. page_alloc_init函数暂时不知其目的
  53. printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);
  54. parse_early_param();
  55. parse_args("Booting kernel", static_command_line, __start___param,
  56. __stop___param - __start___param,
  57. &unknown_bootoption);

点击(此处)折叠或打开

  1. 打印从内核启动参数中获取的cmdline字符串。
  2. 解析cmdline中的启动参数。
  1. /*
  2. * 使用大量bootmem分配,且必须先于
  3. * kmem_cache_init()
  4. */
  5. 点击(此处)折叠或打开
    1. 以上注释的含义在于bootmem是内核启动时使用的临时内存分配器。之后由slab接替。
    2. kmem_cache_init()初始化了内核高速缓存分配器(slab分配器),这个函数标标志着bootmem的终结,同时内核的内存管理系统正式启用了。
    3. 所以在kmem_cache_init()之后,bootmem的API不再可用,所以bootmem分配必须先于kmem_cache_init()。
  6. setup_log_buf(0);
  7. 点击(此处)折叠或打开
    1. 使用bootmem分配一个记录启动信息的缓存区
  8. pidhash_init();
  9. 点击(此处)折叠或打开
    1. 使用bootmem分配并初始化PID散列表,由PID分配器管理空闲和已指派的PID
  10. vfs_caches_init_early();
  11. 点击(此处)折叠或打开
    1. 前期VFS缓存初始化
  12. sort_main_extable();

    点击(此处)折叠或打开

    1. 对内核异常表( exception table )按照异常向量号大小进行排序。
  13. trap_init();

    点击(此处)折叠或打开

    1. 对内核陷阱异常进行初始化,在ARM构架中为空函数。
  14. mm_init();

    点击(此处)折叠或打开

    1. 初始化内核内存分配器,其包含6个子函数,作用如下:
    2. 1、page_cgroup_init_flatmem(); 获取page_cgroup 所需内存
    3. 2、mem_init(); 关闭并释放bootmem分配器,打印内存信息。在内核启动时看到的类似如下信息,就是其子函数mem_init输出的:
    4. 点击(此处)折叠或打开
      1. Memory: 86MB 39MB = 125MB total
      2. Memory: 120768k/120768k available, 99392k reserved, 0K highmem
      3. Virtual kernel memory layout:
      4. vector : 0xffff0000 - 0xffff1000 ( 4 kB)
      5. fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
      6. DMA : 0xffc00000 - 0xffe00000 ( 2 MB)
      7. vmalloc : 0xde800000 - 0xf8000000 ( 408 MB)
      8. lowmem : 0xc0000000 - 0xde400000 ( 484 MB)
      9. pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
      10. modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
      11. .init : 0xc0008000 - 0xc003b000 ( 204 kB)
      12. .text : 0xc003b000 - 0xc04c0000 (4628 kB)
      13. .data : 0xc04c0000 - 0xc0501a80 ( 263 kB)
    5. 3、kmem_cache_init(); 初始化slab分配器
    6. 4、percpu_init_late(); PerCPU变量系统后期初始化
    7. 5、pgtable_cache_init();页表缓存初始化,对于ARM,“介是一个空函数”
    8. 6、vmalloc_init();初始化虚拟内存分配器
  15. /*
  16. * 在开启任何中断(比如定时器中断)前设置调度器。
  17. * 完整的拓扑设置发生在smp_init()中
  18. * -但与此同时,我们仍然有一个正常运作的调度器。
  19. */
  20. sched_init();

    点击(此处)折叠或打开

    1. 初始化调度器数据结构,并创建运行队列
  21. /*
  22. * 禁用强占 - 早期启动时的调度是极为脆弱的,
  23. * 直到cpu_idle()的首次运行。
  24. */
  25. preempt_disable();
  26. if (!irqs_disabled()) {
  27. printk(KERN_WARNING "start_kernel(): bug: interrupts were "
  28. "enabled *very* early, fixing it\n");
  29. local_irq_disable();
  30. }

    点击(此处)折叠或打开

    1. 在启动的初期关闭抢占和中断。
  31. idr_init_cache();
  32. 点击(此处)折叠或打开
    1. 为IDR机制分配缓存,主要是为struct idr_layer结构体分配空间
    2. 参考资料:《浅析linux内核中的idr机制》
  33. perf_event_init();
  34. 点击(此处)折叠或打开
    1. CPU性能监视机制初始化
    2. 此机制包括CPU同一时间执行指令数,cache miss数,分支预测失败次数等性能参数
  35. rcu_init();

    点击(此处)折叠或打开

    1. 内核RCU(Read-Copy Update:读取-复制-更新)机制初始化
  36. radix_tree_init();

    点击(此处)折叠或打开

    1. 内核radix树算法初始化
  37. /* 在init_ISA_irqs()之前初始化一些链接 */
  38. early_irq_init();
  39. init_IRQ();

    点击(此处)折叠或打开

    1. 硬件中断系统初始化:
    2. early_irq_init();前期外部中断描述符初始化,主要初始化数据结构。
    3. init_IRQ;对应构架特定的中断初始化函数,在ARM构架中:
    4. 点击(此处)折叠或打开
      1. void __init init_IRQ(void)
      2. {
      3. machine_desc->init_irq();
      4. }
    5. 也就是运行设备描述结构体中的init_irq函数,此函数一般在板级初始化文件(arch/*/mach-*/board-*.c)中定义。
  40. prio_tree_init();

    点击(此处)折叠或打开

    1. 初始化内核基于radix数的优先级搜索树(PST),主要是对其结构体进行初始化。
  41. init_timers();
  42. hrtimers_init();
  43. softirq_init();
  44. timekeeping_init();
  45. time_init();

    点击(此处)折叠或打开

    1. 以上几个函数主要是初始化内核的软中断及时钟机制:
    2. 前面几个函数主要是注册一些内核通知函数到cpu和hotcpu通知链,并开启部分软中断(tasklet等)。
    3. 最后的time_init是构架相关的,旨在开启一个硬件定时器,开始产生系统时钟。对于ARM构架:

      点击(此处)折叠或打开

      1. void __init time_init(void)
      2. {
      3. system_timer = machine_desc->timer;
      4. system_timer->init();
      5. #ifdef CONFIG_HAVE_SCHED_CLOCK
      6. sched_clock_postinit();
      7. #endif
      8. }
    4. 其实就是调用板级初始化文件(arch/arm/mach-*/board-*.c)中定义“设备描述结构体”中的timer成员的初始化函数。
  46. profile_init();

    点击(此处)折叠或打开

    1. 初始化内核profile子系统,她是内核的性能调试工具。
  47. call_function_init();

    点击(此处)折叠或打开

    1. 初始化所有CPU的call_single_queue(具体作用还没搞明白),并注册CPU热插拔通知函数到CPU通知链中。
  48. if (!irqs_disabled())
  49. printk(KERN_CRIT "start_kernel(): bug: interrupts were "
  50. "enabled early\n");
  51. early_boot_irqs_disabled = false;
  52. local_irq_enable();

    点击(此处)折叠或打开

    1. 检测硬件中断是否开启,如果开启了就打印出警告。
    2. 设置启动早期IRQ使能标志,允许IRQ使能。
    3. 最后开启总中断(ARM构架是这样,其他构架可能也是这个意思)。
  53. /*  中断已经开启,因此所有GFP分配是安全的. */
  54. gfp_allowed_mask = __GFP_BITS_MASK;
  55. 点击(此处)折叠或打开
    1. 开启所有GFP分配允许标志
    2. GFP(get free page)
  56. kmem_cache_init_late();

    点击(此处)折叠或打开

    1. slab分配器的后期初始化。如果使用的是slob或slub,则为空函数。
  57. /*
  58. * HACK ALERT! hack警告!这个是早期的。我们在完成PCI设置等工作前
  59. * 使能控制台,且console_init()必须意识到这个。
  60. * 但是我们的确想要早点输出信息,以防某些错误的发生。
  61. */
  62. console_init();

    点击(此处)折叠或打开

    1. 初始化控制台,这样可以早点看到启动信息,避免出错时无法查找原因。
  63. if (panic_later)
  64. panic(panic_later, panic_param);
  65. 点击(此处)折叠或打开
    1. 检查内核恐慌标志。如果出了问题,就打印信息。
  66. lockdep_info();

    点击(此处)折叠或打开

    1. 打印lockdep调试模块的信息。
  67. /*
  68. * 当irq使能的时候必须运行这个函数,因为它也要自检
  69. * [hard/soft]-irqs 开/关 锁反转的bug:
  70. *
  71. */
  72. locking_selftest();
  73. #ifdef CONFIG_BLK_DEV_INITRD
  74. if (initrd_start && !initrd_below_start_ok &&
  75. page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
  76. printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
  77. "disabling it.\n",
  78. page_to_pfn(virt_to_page((void *)initrd_start)),
  79. min_low_pfn);
  80. initrd_start = 0;
  81. }
  82. #endif

    点击(此处)折叠或打开

    1. 检查initrd的位置是否符合要求。
    2. min_low_pfn是系统可用的最小的pfn(页帧号)。
    3. 也就是判断传递进来initrd_start对应的物理地址是否正常。如果有误就打印错误信息,并清零initrd_start。
  83. page_cgroup_init();

    点击(此处)折叠或打开

    1. mem_cgroup是cgroup体系中提供的用于memory隔离的功能,此处对此功能进行初始化。
    2. 参考资料:《linux内核mem_cgroup浅析》
  84. enable_debug_pagealloc();

    点击(此处)折叠或打开

    1. 使能页分配的调试标志。
  85. debug_objects_mem_init();

    点击(此处)折叠或打开

    1. debug objects机制的内存分配初始化
  86. kmemleak_init();

    点击(此处)折叠或打开

    1. 内核内存泄漏检测机制初始化;
  87. setup_per_cpu_pageset();

    点击(此处)折叠或打开

    1. 设置每个CPU的页组,并初始化。此前只有启动页组。
  88. numa_policy_init();

    点击(此处)折叠或打开

    1. 非一致性内存访问(NUMA)初始化
  89. if (late_time_init)
  90. late_time_init();

    点击(此处)折叠或打开

    1. 如果构架存在此函数,就调用后期时间初始化。
  91. sched_clock_init();

    点击(此处)折叠或打开

    1. 对每个CPU,初始化调度时钟。
  92. calibrate_delay();

    点击(此处)折叠或打开

    1. 计算BogoMIPS值,他是衡量一个CPU性能的标志。
  93. pidmap_init();

    点击(此处)折叠或打开

    1. PID分配映射初始化。
  94. anon_vma_init();

    点击(此处)折叠或打开

    1. 匿名虚拟内存域( anonymous VMA)初始化
  95. #ifdef CONFIG_X86
  96. if (efi_enabled)
  97. efi_enter_virtual_mode();
  98. #endif
  99. thread_info_cache_init();

    点击(此处)折叠或打开

    1. 获取thread_info缓存空间,大部分构架为空函数(包括ARM)
  100. cred_init();

    点击(此处)折叠或打开

    1. 任务信用系统初始化。详见:Documentation/credentials.txt
  101. fork_init(totalram_pages);

    点击(此处)折叠或打开

    1. 进程创建机制初始化。为内核"task_struct"分配空间,计算最大任务数。
  102. proc_caches_init();

    点击(此处)折叠或打开

    1. 初始化进程创建机制所需的其他数据结构,为其申请空间。
  103. buffer_init();

    点击(此处)折叠或打开

    1. 缓存系统初始化,创建缓存头空间,并检查其大小限时。
  104. key_init();

    点击(此处)折叠或打开

    1. 内核密匙管理系统初始化。
  105. security_init();

    点击(此处)折叠或打开

    1. 内核安全框架初始化
  106. dbg_late_init();

    点击(此处)折叠或打开

    1. 内核调试系统后期初始化
  107. vfs_caches_init(totalram_pages);

    点击(此处)折叠或打开

    1. 虚拟文件系统(VFS)缓存初始化
  108. signals_init();

    点击(此处)折叠或打开

    1. 信号管理系统初始化
  109. /* 根文件系统的填充可能需要也回写机制 */
  110. page_writeback_init();

    点击(此处)折叠或打开

    1. 页回写机制初始化
  111. #ifdef CONFIG_PROC_FS
  112. proc_root_init();
  113. #endif

    点击(此处)折叠或打开

    1. proc文件系统初始化
  114. cgroup_init();

    点击(此处)折叠或打开

    1. control group的正式初始化
  115. cpuset_init();

    点击(此处)折叠或打开

    1. CPUSET初始化。
    2. 参考资料:《多核心計算環境—NUMA與CPUSET簡介》
  116. taskstats_init_early();

    点击(此处)折叠或打开

    1. 任务状态早期初始化函数:为结构体获取高速缓存,并初始化互斥机制。
  117. delayacct_init();

    点击(此处)折叠或打开

    1. 任务延迟机制初始化
  118. check_bugs();

    点击(此处)折叠或打开

    1. 检查CPU BUG的函数,通过软件规避BUG
  119. acpi_early_init(); /* 在 LAPIC 和 SMP 前初始化 */

    点击(此处)折叠或打开

    1. ACPI早期初始化函数。
    2. ACPI - Advanced Configuration and Power Interface高级配置及电源接口
  120. sfi_init_late();

    点击(此处)折叠或打开

    1. SFI 初始程序晚期设置函数,
    2. SFI - SIMPLE FIRMWARE INTERFACE。
  121. ftrace_init();

    点击(此处)折叠或打开

    1. 功能跟踪调试机制初始化,ftrace 是 function trace 的简称。
  122. /* 所剩下的非-__init的初始化, 内核现在已经启动了 */
  123.  rest_init();

    点击(此处)折叠或打开

    1. 虽然从名字上来说是剩余的初始化。
    2. 但是这个函数中的初始化包含了很多的内容,后面我回单独写一篇来分析。
  124. }

在看完上面的代码之后,你会发现内容很多。但是归纳起来,我认为需要注意的有以下几点:

  1. 内核启动参数的获取和处理
  2. setup_arch(&command_line);函数
  3. 内存管理的初始化(从bootmem到slab)
  4. rest_init();函数

其他的部分都是对内核各个组件的数据结构申请内存,并初始化。

-----------------------------------------------------------

参考资料:

  1. 《ARM Linux系统启动-start_kernel函数》

    一个很棒的台湾博士生 陳育書关于Linux启动分析的博文

  2. 《深入Linux内核构架》附录D 系统启动
时间: 2024-12-09 18:09:28

Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(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内核源码分析--内核启动之(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,这个函数也做了很多内核和驱动的初始化工作,详解

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内存源码分析 - 内存压缩(一),因为会涉及里面的一些知识. 其实一句话可以概括页面迁移时是如何进行同步的,就是:我要开始对这