在分析start_kernel函数的时候,其中有构架相关的初始化函数setup_arch。

此函数根据构架而异,对于ARM构架的详细分析如下:

  1. void __init setup_arch(char **cmdline_p)
  2. {
  3. struct machine_desc *mdesc;
  4. 点击(此处)折叠或打开

    1. 此为设备描述结构体,对于任何板子都定义了这样的一个结构体,我以前的文章有介绍:
    2. 《Uncompressing Linux... done, booting the kernel》 1、machine type 不匹配
  5. unwind_init();
  6. 点击(此处)折叠或打开

    1. 初始化基於ARM EABI的Backtrace Unwind機制(栈回退),此函数主要用于地址转换(arch/arm/kernel/unwind.c)
  7. setup_processor();

    点击(此处)折叠或打开

    1. 再次检测处理器类型,并初始化处理器相关的底层变量。内核启动时的处理器信息(包括cache)就是通过这个函数打印的,例如:

      1. CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c53c7f
      2. CPU: VIPT nonaliasing data cache, VIPT aliasing instruction cache
  8. mdesc = setup_machine_fdt(__atags_pointer);
  9. if (!mdesc)
  10. mdesc = setup_machine_tags(machine_arch_type);

    点击(此处)折叠或打开

    1. 在此处通过bootloader传递过来的设备ID来匹配一个 struct machine_desc 结构体
    2. (这个结构体就是在arch/arm/mach-*/mach-*.c中定义的结构体:MACHINE_START~MACHINE_END )
    3. 如果没有匹配上就死循环。
    4. 如果匹配上了就打印机器名 ,并处理bootloader传递过来的tagged_list,将所有的tag信息保存到相应的全局变量或结构体中。
    5. 内核启动时的机器信息就是这里打印的,例如:
    6. 点击(此处)折叠或打开

      1. Machine: ti8168evm
    7. 最后返回结构体指针。
  11. machine_desc = mdesc;
  12. machine_name = mdesc->name;

    点击(此处)折叠或打开

    1. 通过匹配的struct machine_desc 结构体数据,初始化一些全局变量
  13. if (mdesc->soft_reboot)
  14. reboot_setup("s");

    点击(此处)折叠或打开

    1. 通过struct machine_desc 中的soft_reboot数据来设置重启类型:
    2. 如果存在就为“s”:softreset;如果不存在就为“h”:hardreset
  15. init_mm.start_code = (unsigned long) _text;
  16. init_mm.end_code = (unsigned long) _etext;
  17. init_mm.end_data = (unsigned long) _edata;
  18. init_mm.brk     = (unsigned long) _end;

    点击(此处)折叠或打开

    1. 这里通过连接脚本中得到的Linux代码位置数据来初始化一个mm_struct结构体init_mm中的部分数据
    2. ps:每一个任务都有一个mm_struct结构以管理内存空间,init_mm是内核自身的mm_struct
  19. /* 同时填充cmd_line以备后用, 保护boot_command_line数据 */
  20. strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
  21. *cmdline_p = cmd_line;

    点击(此处)折叠或打开

    1. 将boot_command_line复制到cmd_line中。这里关键是要知道系统启动的时候的cmdline是如何传递的。
  22. parse_early_param();

    点击(此处)折叠或打开

    1. 处理在 struct obs_kernel_param 中定义为early的启动参数(主要是内存配置部分的参数)
    2. 其中就分析了mem=size@start参数初始化了struct meminfo meminfo;
    3. 同时如果有vmalloc=size参数也会初始化 vmalloc_min
    4. 参考:《Linux内核高-低端内存设置代码跟踪(ARM构架)》
    5. 这里需要注意的是内核的cmdline中的参数按照其被需要的先后,分为early和非early的。
    6. include/linux/init.h:

      点击(此处)折叠或打开

      1. struct obs_kernel_param {
      2. const char *str;            //在cmdline中相应参数名。
      3. int (*setup_func)(char *);  //对于此参数的专用处理函数
      4. int early;                  //是否为早期需要处理的参数
      5. };
    7. 两种不同的参数在内核中用了不同的宏来定义:
    8. early: #define early_param(str, fn) \
    9. __setup_param(str, fn, fn, )
    10. 非early: #define __setup(str, fn) \
    11. __setup_param(str, fn, fn, )
    12. 使用这两个宏定义的参数和构架相关,一些构架或者板子可以定义自己特定的参数和处理函数。对于比较重要的“men”参数就是early参数。
  23. sanity_check_meminfo();

    点击(此处)折叠或打开

    1. 在此处设置struct meminfo meminfo中每个bank中的highmem变量,
    2. 通过vmalloc_min确定每个bank中的内存是否属于高端内存
  24. arm_memblock_init(&meminfo, mdesc);

    点击(此处)折叠或打开

    1. 在此处按地址数据从小到大排序meminfo中的数据,并初始化全局的memblock数据。
  25.     paging_init(mdesc);

    点击(此处)折叠或打开

    1. 设置内核的参考页表。
    2. 此页表不仅用于物理内存映射,还用于管理vmalloc区。
    3. 此函数中非常重要的一点就是初始化了bootmem分配器!
  26. request_standard_resources(mdesc);
  27. 点击(此处)折叠或打开

    1. 通过获取设备描述结构体(struct machine_desc)中的数据和编译时产生的地址数据,初始化内存相关的全局结构体变量
  28. unflatten_device_tree();

    点击(此处)折叠或打开

    1. 通过启动参数中的“非平坦设备树”信息(如果有),获取内存相关信息
  29. #ifdef CONFIG_SMP
  30. if (is_smp())
  31. smp_init_cpus();
  32. #endif

    点击(此处)折叠或打开

    1. 针对SMP处理器,初始化可能存在的CPU映射 - 这描述了可能存在的CPU
  33. reserve_crashkernel();

    点击(此处)折叠或打开

    1. 用于内核崩溃时的保留内核
    2. 此功能通过内核command line参数中的"crashkernel="保留下内存用于主内核崩溃时获取内核信息的导出。
  34. cpu_init();

    点击(此处)折叠或打开

    1. 初始化一个CPU,并设置一个per-CPU栈
  35. tcm_init();

    点击(此处)折叠或打开

    1. 初始化ARM内部的TCM(紧耦合内存)。
    2. 参考资料:《对ARM紧致内存TCM的理解》
    3. ARM官网也有介绍文档
  36. #ifdef CONFIG_MULTI_IRQ_HANDLER
  37. handle_arch_irq = mdesc->handle_irq;
  38. #endif
  39. 点击(此处)折叠或打开

    1. 调用设备描述结构体中的mdesc->handle_irq函数,目的未知。
  40. #ifdef CONFIG_VT
  41. #if defined(CONFIG_VGA_CONSOLE)
  42. conswitchp = &vga_con;
  43. #elif defined(CONFIG_DUMMY_CONSOLE)
  44. conswitchp = &dummy_con;
  45. #endif
  46. #endif
  47. early_trap_init();
  48. 点击(此处)折叠或打开

    1. 对中断向量表进行早期初始化
  49.     if (mdesc->init_early)
  50.         mdesc->init_early();

    点击(此处)折叠或打开

    1. 如果设备描述结构体定义了init_early函数(应该是早期初始化之意),则在这里调用。
  51. }
 
这个函数主要是检查处理器的类型是否匹配,并获取处理器信息来设置处理器的相关底层参数。

  1. static void __init setup_processor(void)
  2. {
  3. struct proc_info_list *list;
  4. /*
  5. * 在支持处理器列表中定位处理器
  6. * 连接器为我们创建这个列表,从                                                                              * arch/arm/mm/proc-*.S中的入口
  7. */
  8. list = lookup_processor_type(read_cpuid_id());
  9. if (!list) {
  10. printk("CPU configuration botched (ID %08x), unable "
  11. "to continue.\n", read_cpuid_id());
  12. while (1);
  13. }

    点击(此处)折叠或打开

    1. 这里再次核对处理器类型,虽然这个已经在汇编代码中执行过一遍了
  14. cpu_name = list->cpu_name;
  15. #ifdef MULTI_CPU
  16. processor = *list->proc;
  17. #endif
  18. #ifdef MULTI_TLB
  19. cpu_tlb = *list->tlb;
  20. #endif
  21. #ifdef MULTI_USER
  22. cpu_user = *list->user;
  23. #endif
  24. #ifdef MULTI_CACHE
  25. cpu_cache = *list->cache;
  26. #endif
  27. 点击(此处)折叠或打开

    1. 通过从struct proc_info_list获取的数据初始化CPU相关的全局变量
  28. printk("CPU: %s [%08x] revision %d (ARMv%s), cr=%08lx\n",
  29. cpu_name, read_cpuid_id(), read_cpuid_id() & 15,
  30. proc_arch[cpu_architecture()], cr_alignment);
  31. 点击(此处)折叠或打开

    1. 打印内核启动时的处理器信息
  32. sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
  33. sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
  34. elf_hwcap = list->elf_hwcap;
  35. #ifndef CONFIG_ARM_THUMB
  36. elf_hwcap &= ~HWCAP_THUMB;
  37. #endif
  38. feat_v6_fixup();
  39. 点击(此处)折叠或打开

    1. 针对特定的ARM核软件屏蔽一些功能
  40. cacheid_init();

    点击(此处)折叠或打开

    1. 初始化ARM核中的缓存
  41. cpu_proc_init();

    点击(此处)折叠或打开

    1. 宏:
    2. #define cpu_proc_init __glue(CPU_NAME,_proc_init)
    3. 意在调用处理器特定的初始化函数。
  42. }

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

  1. 鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源 | 百篇博客分析OpenHarmonyOS | v2.07

    百篇博客系列篇.本篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管理内核资源 | 51.c.h .o 进程管理相关篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管理内核 ...

  2. Linux内核源码分析 day01——内存寻址

    前言 Linux内核源码分析 Antz系统编写已经开始了内核部分了,在编写时同时也参考学习一点Linux内核知识. 自制Antz操作系统 一个自制的操作系统,Antz .半图形化半命令式系统,同时嵌入 ...

  3. 鸿蒙内核源码分析(根文件系统) | 先挂到`/`上的文件系统 | 百篇博客分析OpenHarmony源码 | v66.01

    百篇博客系列篇.本篇为: v66.xx 鸿蒙内核源码分析(根文件系统) | 先挂到/上的文件系统 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

  4. 鸿蒙内核源码分析(文件概念篇) | 为什么说一切皆是文件 | 百篇博客分析OpenHarmony源码 | v62.01

    百篇博客系列篇.本篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一切皆是文件 | 51.c.h.o 本篇开始说文件系统,它是内核五大模块之一,甚至有Linux的设计哲学是" ...

  5. 鸿蒙内核源码分析(GN应用篇) | GN语法及在鸿蒙的使用 | 百篇博客分析OpenHarmony源码 | v60.01

    百篇博客系列篇.本篇为: v60.xx 鸿蒙内核源码分析(gn应用篇) | gn语法及在鸿蒙的使用 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙 ...

  6. 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 百篇博客分析OpenHarmony源码 | v51.04

    百篇博客系列篇.本篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | ...

  7. 鸿蒙内核源码分析(信号生产篇) | 信号安装和发送过程是怎样的? | 百篇博客分析OpenHarmony源码 | v48.03

    百篇博客系列篇.本篇为: v48.xx 鸿蒙内核源码分析(信号生产篇) | 年过半百,依然活力十足 | 51.c.h .o 进程管理相关篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁在管 ...

  8. 鸿蒙内核源码分析(特殊进程篇) | 龙生龙,凤生凤,老鼠生儿会打洞 | 百篇博客分析OpenHarmony源码 | v46.02

    百篇博客系列篇.本篇为: v46.xx 鸿蒙内核源码分析(特殊进程篇) | 龙生龙凤生凤老鼠生儿会打洞 | 51.c.h .o 进程管理相关篇为: v02.xx 鸿蒙内核源码分析(进程管理篇) | 谁 ...

  9. 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 百篇博客分析OpenHarmony源码 | v13.02

    百篇博客系列篇.本篇为: v13.xx 鸿蒙内核源码分析(源码注释篇) | 鸿蒙必定成功,也必然成功 | 51.c.h .o 几点说明 kernel_liteos_a_note | 中文注解鸿蒙内核 ...

  10. 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 百篇博客分析OpenHarmony源码 | v70.01

    百篇博客系列篇.本篇为: v70.xx 鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

随机推荐

  1. 解决p4c安装时protobuf未定义引用的错误

    安装好p4c的依赖之后,执行make -j2时出现以下问题: undefined references to `google::protobuf::internal::LogMessage::oper ...

  2. 基于RYU restful api实现的VLAN网络虚拟化

    基于RYU restful api实现的VLAN网络虚拟化 前言 本次实验是基于OVS的VLAN虚拟化简易实践方案的进一步的实验,采用RYU restful api进行配置.本质上和上次实验没什么差, ...

  3. 腾讯云申请的64位ubuntu服务器配置php环境

    腾讯云申请的64位ubuntu服务器配置php环境 一.首先还是安装Lamp组合 Linux+Apache+Mysql+php 直接命令 sudo apt-get install apache2 su ...

  4. Beta版本冲刺(三)

    目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...

  5. ElasticSearch 2 (8) - 概览与简介

    ElasticSearch 2 (8) - 概览与简介 摘要 分布式集群架构,具有高扩充性,可随时增加或移除节点,并保证数据正确. 使用Apache Lucene储存JSON文件,提供全文搜索功能 所 ...

  6. opencv图像识别技术在自动化测试中的应用

    在自动化测试中,基于xpath.js选择器.css选择器进行元素定位及判定的技术已经比较成熟.在实际应用中,无论是web端还是移动端,仍有很多时候需要根据页面内容.页面中的图像进行定位及判定,这里介绍 ...

  7. Linux学习之CentOS(二)----远程登录管理工具SecureCRT的使用

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  8. 2019 front-end web trending

    2019 front-end web trending https://github.com/kamranahmedse/developer-roadmap https://raw.githubuse ...

  9. Spring之c3p0连接池xml配置和使用举例

    1.导入jar包 c3p0-0.9.5.2.jar mchange-commons-java-0.2.11.jar 2.源码: beans.xml <beans xmlns="http ...

  10. java 方法的返回类型

    定义了返回值类型后 必须要执行 return 因为 当一个变量初始化时候 需要有数据 如果方法体里面没有返回数据类型时 这个变量是没有数据的 会报错 所以必须要返回一个数据 当一个方法体里面有 if ...