您的位置:首页 > 运维架构 > Linux

linux内核启动第二阶段分析-setup_arch()函数

2013-03-08 21:36 525 查看
执行setup_arch()函数

回到start_kernel当中,488行,调用setup_arch函数,传给他的参数是那个未被初始化的内部变量command_line。这个setup_arch()函数是start_kernel阶段最重要的一个函数,每个体系都有自己的setup_arch()函数,是体系结构相关的,具体编译哪个体系的setup_arch()函数,由顶层Makefile中的ARCH变量决定:

它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过 bootmem_init()函数根据系统定义的 meminfo 结构进行内存结构的初始化,最后调用paging_init()开启 MMU,创建内核页表,映射所有的物理内存和 IO空间。

start_kernel ()

--> setup_arch ()

--> paging_init ()

--> bootmem_init ()

--> alloc_bootmem_low_pages ()

arch/arm/kernel/setup.c

877 void __init setup_arch(char **cmdline_p)

878 {

879 struct machine_desc *mdesc;

880

881 unwind_init(); //本架构中没有用

882

883 setup_processor();//汇编的CPU初始化部分

884 mdesc = setup_machine_fdt(__atags_pointer);//__atags_pointer是bootloader传递参数的物理地址

885 if (!mdesc)

886 mdesc = setup_machine_tags(machine_arch_type);

887 machine_desc = mdesc;

888 machine_name = mdesc->name;

889

890 if (mdesc->soft_reboot)

891 reboot_setup("s");

892

893 init_mm.start_code = (unsigned long) _text;

894 init_mm.end_code = (unsigned long) _etext;

895 init_mm.end_data = (unsigned long) _edata;

896 init_mm.brk = (unsigned long) _end;

897

898 /* populate cmd_line too for later use, preserving boot_command_line */

899 strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);

900 *cmdline_p = cmd_line;

901

902 parse_early_param();

903

904 sanity_check_meminfo();

905 arm_memblock_init(&meminfo, mdesc);

906

907 paging_init(mdesc);

908 request_standard_resources(mdesc);

909

910 unflatten_device_tree();

911

912 #ifdef CONFIG_SMP

913 if (is_smp())

914 smp_init_cpus();

915 #endif

916 reserve_crashkernel();

917

918 cpu_init();//此函数为空

919 tcm_init();

920

921 #ifdef CONFIG_MULTI_IRQ_HANDLER

922 handle_arch_irq = mdesc->handle_irq;

923 #endif

924

925 #ifdef CONFIG_VT

926 #if defined(CONFIG_VGA_CONSOLE)

927 conswitchp = &vga_con;

928 #elif defined(CONFIG_DUMMY_CONSOLE)

929 conswitchp = &dummy_con;

930 #endif

931 #endif

932 early_trap_init();//重定位中断向量,将中断向量代码拷贝到中断向量页,并把信号处理代码指令拷贝到向量页中

933

934 if (mdesc->init_early)

935 mdesc->init_early();

936 }

879行完整的machine_desc结构描述如下:arch/arm/include/asm/mach/arch.h

13 struct tag;

14 struct meminfo;

15 struct sys_timer;

16

17 struct machine_desc {

18 unsigned int nr; /*
开发板的机器类型ID*/

19 const char *name; /*
开发板名称 */

20 unsigned long boot_params; /*
内核启动参数的地址*/

21 const char **dt_compat; /* array of device tree

22 * 'compatible' strings */

23

24 unsigned int nr_irqs; /* number of IRQs */

25

26 unsigned int video_start; /* start of video RAM */

27 unsigned int video_end; /* end of video RAM */

28

29 unsigned int reserve_lp0 :1; /* never has lp0 */

30 unsigned int reserve_lp1 :1; /* never has lp1 */

31 unsigned int reserve_lp2 :1; /* never has lp2 */

32 unsigned int soft_reboot :1; /* soft reboot */

33 void (*fixup)(struct machine_desc *,

34 struct tag *, char **,

35 struct meminfo *);

36 void (*reserve)(void);/* reserve mem blocks */

37 void (*map_io)(void);/*
IO映射函数(在这里修改时钟频率)*/

38 void (*init_early)(void);

39 void (*init_irq)(void); /*中断初始化函数*/

40 struct sys_timer *timer; /* system tick timer */

41 void (*init_machine)(void);

42 #ifdef CONFIG_MULTI_IRQ_HANDLER

43 void (*handle_irq)(struct pt_regs *);

44 #endif

45 };

884行__atags_pointer是bootloader传递参数的物理地址,见第一阶段启动源码第100行(str r2, [r6]),此处r6就是__atags_pointer的地址,它将bootloader通过r2传递过来的地址参数存放到__atags_pointer。

下面我们来看setup_machine_fdt函数,它在arch/arm/kernel/devtree.c中定义如下:

71 struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)

72 {

73 struct boot_param_header *devtree;

74 struct machine_desc *mdesc, *mdesc_best = NULL;

75 unsigned int score, mdesc_score = ~1;

76 unsigned long dt_root;

77 const char *model;

78

79 if (!dt_phys)

80 return NULL;

81

82 devtree = phys_to_virt(dt_phys);//由于MMU单元已打开,此处__atags_pointer是物理地址,需要转换成虚拟地址才能访问,因为此时CPU访问的都是虚拟地址

83

84 /* check device tree validity */

85 if (be32_to_cpu(devtree->magic) != OF_DT_HEADER)

86 return NULL;

87

88 /* Search the mdescs for the 'best' compatible value match */

89 initial_boot_params = devtree;

90 dt_root = of_get_flat_dt_root(); 该函数用来查找在dtb中的根节点

91 for_each_machine_desc(mdesc) {

92 score = of_flat_dt_match(dt_root, mdesc->dt_compat);

93 if (score > 0 && score < mdesc_score) {

94 mdesc_best = mdesc;

95 mdesc_score = score;

96 }

97 }

98 if (!mdesc_best) {

99 const char *prop;

100 long size;

101

102 early_print("\nError: unrecognized/unsupported "

103 "device tree compatible list:\n[ ");

104

105 prop = of_get_flat_dt_prop(dt_root, "compatible", &size);

106 while (size > 0) {

107 early_print("'%s' ", prop);

108 size -= strlen(prop) + 1;

109 prop += strlen(prop) + 1;

110 }

111 early_print("]\n\n");

112

113 dump_machine_table(); /* does not return */

114 }

115

116 model = of_get_flat_dt_prop(dt_root, "model", NULL);

117 if (!model)

118 model = of_get_flat_dt_prop(dt_root, "compatible", NULL);

119 if (!model)

120 model = "<unknown>";

121 pr_info("Machine: %s, model: %s\n", mdesc_best->name, model);

122

123 /* Retrieve various information from the /chosen node */

124 of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);

125 /* Initialize {size,address}-cells info */

126 of_scan_flat_dt(early_init_dt_scan_root, NULL);

127 /* Setup memory, calling early_init_dt_add_memory_arch */

128 of_scan_flat_dt(early_init_dt_scan_memory, NULL);

129

130 /* Change machine number to match the mdesc we're using */

131 __machine_arch_type = mdesc_best->nr;

132

133 return mdesc_best;

134 }

boot_param_header结构在include/linux/of_fdt.h第44行定义如下:

struct boot_param_header {

__be32 magic; /* magic word OF_DT_HEADER */

__be32 totalsize; /* total size of DT block */

__be32 off_dt_struct; /* offset to structure */

__be32 off_dt_strings; /* offset to strings */

__be32 off_mem_rsvmap; /* offset to memory reserve map */

__be32 version; /* format version */

__be32 last_comp_version; /* last compatible version */

/* version 2 fields below */

__be32 boot_cpuid_phys; /* Physical CPU id we're booting on */

/* version 3 fields below */

__be32 dt_strings_size; /* size of the DT strings block */

/* version 17 fields below */

__be32 dt_struct_size; /* size of the DT structure block */

};

第89行initial_boot_params在同文件下第436行有定义struct boot_param_header *initial_boot_params;

第90行of_get_flat_dt_root()函数用来查找在dtb中的根节点(drivers/of/fdt.c)

unsigned long __init of_get_flat_dt_root(void)

{

unsigned long p = ((unsigned long)initial_boot_params) +

be32_to_cpu(initial_boot_params->off_dt_struct);

while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)

p += 4;

BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);

p += 4;

return ALIGN(p + strlen((char *)p) + 1, 4);

}

第91行在arch/arm/include/asm/mach/arch.h中定义如下

55 extern struct machine_desc __arch_info_begin[], __arch_info_end[];

56 #define for_each_machine_desc(p) \

57 for (p = __arch_info_begin; p < __arch_info_end; p++)

58

59 /*

60 * Set of macros to define architecture features. This is built into

61 * a table by the linker.

62 */

63 #define MACHINE_START(_type,_name) \

64 static const struct machine_desc __mach_desc_##_type \

65 __used \

66 __attribute__((__section__(".arch.info.init"))) = { \

67 .nr = MACH_TYPE_##_type, \

68 .name = _name,

69

70 #define MACHINE_END \

71 };

int __init of_flat_dt_match(unsigned long node, const char **compat)

{

return of_fdt_match(initial_boot_params, node, compat);

}

如果node与兼容表中的值匹配则返回真

int of_fdt_match(struct boot_param_header *blob, unsigned long node,

const char **compat)

{

unsigned int tmp, score = 0;

if (!compat)

return 0;

while (*compat) {

tmp = of_fdt_is_compatible(blob, node, *compat);

if (tmp && (score == 0 || (tmp < score)))

score = tmp;

compat++;

}

return score;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: