内核head.s对dtb的简单处理
bootloader启动内核时,会设置r0,r1,r2三个寄存器,r0一般设置为0,r1一般设置为machine_id(在使用设备树时改参数没有被使用),r2一般设置ATAGS或DTB的起始地址,比如我们SMDK2410,SMDK2440,JZ2440都对应有一个machine_desc结构体,该结构体包含有nr和init初始化函数,当bootloader传递的machine_id给内核时,内核会根据这个machine_id和machine_desc结构体中的nr比对,如果一致的化则调用init初始化函数初始化单板,现在我们有了设备树,machine_id的设置就由设备树来完成,下面来简要介绍下head.s的启动流程
1.
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
mrc p15, 0, r9, c0, c0用来获取处理器ID,__lookup_processor_type用来查找处理器类型,看看内核是否支持这个CPU,如果支持的话就调用这款CPU对应的初始化函数
2.
/*
* r1 = machine no, r2 = atags or dtb,
* r8 = phys_offset, r9 = cpuid, r10 = procinfo
*/
bl __vet_atags
#ifdef CONFIG_SMP_ON_UP
bl __fixup_smp
r1里面存放的是机器ID,r2里面要么是atags,要么是dtb首地址,__vet_atags用来判断atags或者dtb是否有效,根据头部信息判断
3
__create_page_tables
创建页表, 即创建虚拟地址和物理地址的映射关系
4
__enable_mmu
使能MMU, 以后就要使用虚拟地址了
5.
__mmap_switched
__enable_mmu 后会调用该函数,将r0保存到processor_id,r1保存到machine_arch_type,把bootloader传入的r2参数, 保存到变量__atags_pointer中,调用C函数start_kernel
设备树中对平台信息的处理
/ {
model = "SMDK24440";
compatible = "samsung,smdk2440";
#address-cells = <1>;
#size-cells = <1>;
memory {
/* /memory */
device_type = "memory";
reg = <0x30000000 0x4000000 0 4096>;
};
在前面我们说过,uboot会通过ATAGS传给内核一个机器ID,内核会根据这个机器ID找到machine_desc,调用machine_desc的init函数,现在我们引入设备树后在根节点中的model和compatible,也就是说在dts中会声明想要什么样的machine_desc,根据根节点的compatible属性,内核依据这些字符串(“samsung,smdk2440”)找到machine_desc,compatible属性后面跟着的字符串可以有多个(从头到尾依次匹配),看到下面March_smdk2440.c代码
在内核源码中MACHINE_START定义一个结构体,里面有各项成员和初始化函数,smdk2440_dt_compt表明可以支持哪些单板,里面含有的字符串和我们设备树的根节点compatible属性的value匹对,一致则调用初始化单板函数,当有多个machine_desc跟dts吻合,应该选择第一个匹配到的machine_desc