执行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 = "";
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;
}
阅读(739) | 评论(0) | 转发(0) |