九鼎创展论坛中文版English
登录 | 立即注册 设为首页收藏本站 切换到宽版
查看: 6146|回复: 2
打印 上一主题 下一主题

x4412&ibox项目实战7-Linux内核的引导

[复制链接]
跳转到指定楼层
楼主
发表于 2014-9-22 15:45:01 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
linux的启动框架如下:

linux的内核映像文件zImage本身是一个压缩的文件,在arch/arm/boot/Makefile中,我们可以找到如下语句:
  1. $(obj)/zImage:     $(obj)/compressed/vmlinux FORCE
  2.          $(call if_changed,objcopy)
  3.          @echo '  Kernel: $@ is ready'
复制代码
       可见,zImage是由arch\arm\boot\compressed\vmlinux二进制文件转化而来。在arch/arm/boot/compressed/Makefile中,有如下语句:
  1. $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
  2.                  $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
  3.          $(call if_changed,ld)

  4. $(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
  5.          $(call if_changed,$(suffix_y))

  6. $(obj)/piggy.$(suffix_y).o:  $(obj)/piggy.$(suffix_y) FORCE
复制代码
       由此可以分析得知,zImage是由vmlinux.ldshead.omisc.o以及压缩的内核piggy.gzip.o组成。也就是说,zImage文件即包含了未压缩部分,如head.o,misc.o,也包含了压缩的部分,如piggy.gzip.o。那么,zImage的程序入口在哪里呢?
       arch\arm\boot\compressed\vmlinux.lds中,可以看到其框架如下:
  1. OUTPUT_ARCH(arm)
  2. ENTRY(_start)
  3. SECTIONS
  4. {
  5. ……
  6.   . = 0;
  7.   _text = .;

  8.   .text : {
  9.     _start = .;
  10.     *(.start)
  11.     *(.text)
  12.     *(.text.*)
  13.     *(.fixup)
  14.     *(.gnu.warning)
  15.     *(.rodata)
  16.     *(.rodata.*)
  17.     *(.glue_7)
  18.     *(.glue_7t)
  19.     *(.piggydata)
  20.     . = ALIGN(4);
  21.   }
  22. ……
  23. }
复制代码
       可以看出,其入口点为_start,程序arch\arm\boot\compressed\head.S会首先被执行,在head.S中,程序执行了一堆准备工作后,开始调用misc.c中的decompress_kernel函数,开始解压内核。其函数如下:
  1. void
  2. decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
  3.                    unsigned long free_mem_ptr_end_p,
  4.                    int arch_id)
  5. {
  6.          int ret;

  7.          output_data                   = (unsigned char *)output_start;
  8.          free_mem_ptr               = free_mem_ptr_p;
  9.          free_mem_end_ptr        = free_mem_ptr_end_p;
  10.          __machine_arch_type   = arch_id;

  11.          arch_decomp_setup();

  12.          putstr("Uncompressing Linux...");
  13.          ret = do_decompress(input_data, input_data_end - input_data,
  14.                                 output_data, error);
  15.          if (ret)
  16.                    error("decompressor returned an error");
  17.          else
  18.                    putstr(" done, booting the kernel.\n");
  19. }
复制代码
       这里有几句经典的打印信息:
  1. Uncompressing Linux... done, booting the kernel.
复制代码
       执行完这个后,程序将会跳到init/main.c中,执行经典的start_kernel函数。start_kernel()会调用一系列初始化函数来设置中断,执行进一步的内存配置等,其函数原型如下:
  1. asmlinkage void __init start_kernel(void)
  2. {
  3.          char * command_line;
  4.          extern const struct kernel_param __start___param[], __stop___param[];

  5.          smp_setup_processor_id();//返回启动的CPU的ID号,如为单核则什么也不做

  6.          /*
  7.           * Need to run as early as possible, to initialize the
  8.           * lockdep hash:
  9.           */
  10.          lockdep_init();
  11.          debug_objects_early_init();

  12.          /*
  13.           * Set up the the initial canary ASAP:
  14.           */
  15.          boot_init_stack_canary();

  16.          cgroup_init_early();

  17.          local_irq_disable();//关闭当前CPU的中断
  18.          early_boot_irqs_disabled = true;

  19. /*
  20. * Interrupts are still disabled. Do necessary setups, then
  21. * enable them
  22. */
  23.          tick_init();
  24.          boot_cpu_init();
  25.          page_address_init();//初始化页地址,使用链表将其链接起来
  26.          printk(KERN_NOTICE "%s", linux_banner);//打印内核版本信息
  27.          setup_arch(&command_line);//设置体系结构,由内核根目录的Makefile决定
  28.          mm_init_owner(&init_mm, &init_task);
  29.          mm_init_cpumask(&init_mm);
  30.          setup_command_line(command_line);
  31.          setup_nr_cpu_ids();
  32.          setup_per_cpu_areas();
  33.          smp_prepare_boot_cpu();      /* arch-specific boot-cpu hooks */

  34.          build_all_zonelists(NULL);
  35.          page_alloc_init();

  36.          printk(KERN_NOTICE "Kernel command line: %s\n", boot_command_line);//打印命令行信息
  37.          parse_early_param();//解析内核选项
  38.          parse_args("Booting kernel", static_command_line, __start___param,
  39.                       __stop___param - __start___param,
  40.                       &unknown_bootoption);
  41.          /*
  42.           * These use large bootmem allocations and must precede
  43.           * kmem_cache_init()
  44.           */
  45.          setup_log_buf(0);
  46.          pidhash_init();
  47.          vfs_caches_init_early();
  48.          sort_main_extable();
  49.          trap_init();
  50.          mm_init();

  51.          /*
  52.           * Set up the scheduler prior starting any interrupts (such as the
  53.           * timer interrupt). Full topology setup happens at smp_init()
  54.           * time - but meanwhile we still have a functioning scheduler.
  55.           */
  56.          sched_init();//进程调度器初始化
  57.          /*
  58.           * Disable preemption - early bootup scheduling is extremely
  59.           * fragile until we cpu_idle() for the first time.
  60.           */
  61.          preempt_disable();//禁止内核抢占
  62.          if (!irqs_disabled()) {//检查中断是否已经打开,如果已经打开,则关闭中断
  63.                    printk(KERN_WARNING "start_kernel(): bug: interrupts were "
  64.                                      "enabled *very* early, fixing it\n");
  65.                    local_irq_disable();
  66.          }
  67.          idr_init_cache();
  68.          perf_event_init();
  69.          rcu_init();//初始化RCU(Read-Copy Update)机制
  70.          radix_tree_init();
  71.          /* init some links before init_ISA_irqs() */
  72.          early_irq_init();
  73.          init_IRQ();//中断向量初始化
  74.          prio_tree_init();
  75.          init_timers();//初始化定时器相关的数据结构
  76.          hrtimers_init();//对高精度时钟进行初始化
  77.          softirq_init();//初始化tasklet_softirq和hi_softirq
  78.          timekeeping_init();
  79.          time_init();//初始化系统时钟源
  80.          profile_init();//对内核的profile(一个内核性能调式工具)功能进行初始化
  81.          call_function_init();
  82.          if (!irqs_disabled())
  83.                    printk(KERN_CRIT "start_kernel(): bug: interrupts were "
  84.                                       "enabled early\n");
  85.          early_boot_irqs_disabled = false;
  86.          local_irq_enable();

  87.          /* Interrupts are enabled now so all GFP allocations are safe. */
  88.          gfp_allowed_mask = __GFP_BITS_MASK;

  89.          kmem_cache_init_late();

  90.          /*
  91.           * HACK ALERT! This is early. We're enabling the console before
  92.           * we've done PCI setups etc, and console_init() must be aware of
  93.           * this. But we do want output early, in case something goes wrong.
  94.           */
  95.          console_init();// 初始化控制台以显示printk的内容,在此之前调用的printk只是把数据存到缓冲区里
  96.          if (panic_later)
  97.                    panic(panic_later, panic_param);

  98.          lockdep_info();

  99.          /*
  100.           * Need to run this when irqs are enabled, because it wants
  101.           * to self-test [hard/soft]-irqs on/off lock inversion bugs
  102.           * too:
  103.           */
  104.          locking_selftest();

  105. #ifdef CONFIG_BLK_DEV_INITRD
  106.          if (initrd_start && !initrd_below_start_ok &&
  107.              page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
  108.                    printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - "
  109.                        "disabling it.\n",
  110.                        page_to_pfn(virt_to_page((void *)initrd_start)),
  111.                        min_low_pfn);
  112.                    initrd_start = 0;
  113.          }
  114. #endif
  115.          page_cgroup_init();
  116.          enable_debug_pagealloc();
  117.          debug_objects_mem_init();
  118.          kmemleak_init();
  119.          setup_per_cpu_pageset();
  120.          numa_policy_init();
  121.          if (late_time_init)
  122.                    late_time_init();
  123.          sched_clock_init();
  124.          calibrate_delay();
  125.          pidmap_init();
  126.          anon_vma_init();
  127. #ifdef CONFIG_X86
  128.          if (efi_enabled)
  129.                    efi_enter_virtual_mode();
  130. #endif
  131.          thread_info_cache_init();
  132.          cred_init();
  133.          fork_init(totalram_pages);
  134.          proc_caches_init();
  135.          buffer_init();
  136.          key_init();
  137.          security_init();
  138.          dbg_late_init();
  139.          vfs_caches_init(totalram_pages);//虚拟文件系统的初始化
  140.          signals_init();
  141.          /* rootfs populating might need page-writeback */
  142.          page_writeback_init();
  143. #ifdef CONFIG_PROC_FS
  144.          proc_root_init();
  145. #endif
  146.          cgroup_init();
  147.          cpuset_init();
  148.          taskstats_init_early();
  149.          delayacct_init();

  150.          check_bugs();

  151.          acpi_early_init(); /* before LAPIC and SMP init */
  152.          sfi_init_late();

  153.          ftrace_init();

  154.          /* Do the rest non-__init'ed, we're now alive */
  155.          rest_init();
  156. }
复制代码
       start_kernel函数大致执行任务如下:
输出Linux版本信息,设置与体系结构相关的环境,页表结构初始化,初始化系统IRQ,核心进程调度器初始化,时间、定时器初始化,提取并分析核心启动参数,控制台初始化,剖析器数据结构初始化,核心Cache初始化,延迟校准,内存初始化,创建文件,目录cache,创建与虚拟内存相关的cache,块设备读写缓冲区初始化,创建页cache,创建信号队列cache,初始化内存inode表,创建内存文件描述符表,检查体系结构,SMP机器除引导CPU之外的CPU初始化,创建第一个核心线程,调用init函数,调用cpu_idle()等待调度。
作为核心线程的init()函数完成外设及其驱动程序的加载和初始化,挂接根文件系统。init()打开/dev/console设备,重定向stdin、stdout和stderr到控制台。之后,它搜索文件系统中的init程序(也可以由“init=”命令行参数指定init程序),并使用execve()系统调用执行init程序。搜索init程序的顺序为/sbin/init、/etc/init、/bin/init 和/bin/sh。在嵌入式系统中,多数情况下,可以给内核传入一个简单的shell脚本来启动必需的嵌入式应用程序。
至此,漫长的 Linux 内核引导和启动过程就结束了,而init()对应的由start_kernel()
创建的第一个线程也进入用户模式。
回复

使用道具 举报

沙发
发表于 2014-9-22 22:00:37 | 只看该作者
暂时还没学到,稍微看看,九鼎的代码是我见过的做开发板写的最漂亮的~~~xboot应该是大神啊~~~
回复 支持 反对

使用道具 举报

板凳
发表于 2015-9-16 14:27:34 | 只看该作者
分析的非常适合学习,非常感谢~
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳市九鼎创展科技官方论坛 ( 粤ICP备11028681号-2  

GMT+8, 2024-5-5 20:29 , Processed in 0.021522 second(s), 19 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表