1.内核如何进行多平台的适配,在内核中是如何认识这些板子的?结构体 machine_desc
2.内核启动的整体流程
3.认识一种高效的编程结构
链接脚本:vmlinux.lds.S
.init.arch.info : {
__arch_info_begin = .;
*(.arch.info.init) //代码段
__arch_info_end = .;
}
ARCH.H 宏定义
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
各种板子的BSP文件中出现的宏定义调用
MACHINE_START(SMDK4212, "SMDK4212")
/* Maintainer: Kukjin Kim
.atag_offset = 0x100,
.init_irq = exynos4_init_irq,
.map_io = smdk4x12_map_io,
.handle_irq = gic_handle_irq,
.init_machine = smdk4x12_machine_init,
.timer = &exynos4_timer,
.restart = exynos4_restart,
MACHINE_END
宏展开:
#define MACHINE_START(SMDK4212, "SMDK4212")
static const struct machine_desc __mach_desc_SMDK4212 \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_SMDK4212, \
.name = "SMDK4212",
.atag_offset = 0x100,
.init_irq = exynos4_init_irq,
.map_io = smdk4x12_map_io,
.handle_irq = gic_handle_irq,
.init_machine = smdk4x12_machine_init,
.timer = &exynos4_timer,
.restart = exynos4_restart,
};
总结 machine_desc结构体,用于Linux做设备的识别结构体,这些结构体被限定在了内存的某一片区域
并且通过UBOOT传过来的参数进行该结构体的配置(通过检索taglist的方式来设置)
并且在移植Linux的时候 也要对结构体的变量进行赋值
并且在之后的启动或其他函数中 对该结构体的变量进行调用
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
__lookup_processor_type:
adr r3, __lookup_processor_type_data
__lookup_processor_type_data:
.long .
.long __proc_info_begin
.long __proc_info_end
.size __lookup_processor_type_data, . - __lookup_processor_type_data
VMLINUX_SYMBOL(__proc_info_begin) = .; \
*(.proc.info.init) \
VMLINUX_SYMBOL(__proc_info_end) = .;
__mmap_switched 将旧的地址转化为虚拟地址 代码重定义
start_kernel:
setup_arch(&command_line)
setup_processor()
struct proc_info_list *list;//创建一个CPU指令集描述结构体
list = lookup_processor_type(read_cpuid_id());//从指定的内存中获取到该描述结构体
cpu_name = list->cpu_name;//将获取到的CPU名字赋值给一个全局变量
setup_machine_fdt(__atags_pointer);//找到一个移植Linux时写的最合适的machine_desc结构体 并且返回
for_each_machine_desc(mdesc) {
score = of_flat_dt_match(dt_root, mdesc->dt_compat);
if (score > 0 && score < mdesc_score) {
mdesc_best = mdesc;
mdesc_score = score;
}
}