3.1内核对设备树的处理——从源头分析_内核head.S对dtb的简单处理

本章(第三章)内容是设备树讲解中最重要的一章

设备树文件里面描述的信息可以分为以下三部分

  1. platform identification(平台信息);
  2. runtime configuration(运行时的配置信息);
  3. device population(设备的特性);

实际上,内核对于设备树的处理也会分为三部分:

bootloader启动内核时,会设置r0,r1,r2三个寄存器,通过这三个寄存器将一些参数传给内核。其中:

  • r0一般设置为0;
  • r1一般设置为machine id在使用设备树时该参数没有用到);
  • r2一般设置为ATAGSDTB的开始地址

问:machine id的作用是什么呢?

答:一个内核镜像uImage通常可以支持多种单板,如smdk2410,smdk2440,jz2440,这三种单板之间都有一些微小的差别,也就是说它们分别需要不同的初始化函数

在内核代码中,它们都有一个用于描述自己的machine_desc结构体,里面有对应的初始化函数,还有一个nrnumber)。

那么,当内核启动时,内核怎么知道它在哪个板子上运行,需要调用哪个初始化参数呢?

这就需要用uboot了,uboot需要把machine id传给内核,内核再根据uboot传入的machine id来匹配machine_desc结构体中的nr,如果两者相等就是匹配成功,就会调用对应machine_desc结构体中的初始化函数。

上面是没有使用设备树时的情况,在使用设备树时,r1可以不设置了,也就是不传入machine id,此时,r1可以随便设置。

r2设备树ATAGS起始地址,ATAGS就是之前说的uboot向内核传参数的tag的起始地址。这里需要注意的就是,r2传入的可能是设备树的起始地址,也可能是tag的起始地址。

tag就是uboot对内核传入的启动参数, 对于tag,可以从下列课程处了解更多的相关信息。

下面大致看一下head.S

首先会获取processor id(r9 = processor id),然后跳到__lookup_processor_type,看看内核能不能支持这款CPU。

如果内核能够支持这款CPU的话,r5会返回一个用于描述处理器的结构体(proc_info_list)的地址,否则,r5=0。

在代码里面,有很多.S文件,这些文件里面包含proc_info_list结构体(里面含有这类CPU的初始化函数、信息),也包含cpu id

将读到的cpu id与cpu_mask与,然后再与.S文件中的cpu_val对比,相等说明匹配成功。

 然后往下执行,有一个__vet_atags函数,这个函数就会判断r2传入的是tag的首地址还是dtb文件的首地址

 

然后是__create_page_tables,这个主要是创建页表,也就是创建虚拟地址与物理地址的映射关系,这个先不深入。

继续向下,会使能MMU,使能MMU之后就要使用虚拟地址了。

进入__mmap_switched

进入 __mmap_switched_data,可以看到里面都是一些变量和段的地址(C变量在汇编文件中出现时,变量名表示的该变量的地址)。

继续往下,会从__mmap_switched_data中读值,经过第4步后会将C变量__atags_pointer的地址读到r2

最后,再将之前保存到r8tag或dtb首地址赋给地址为r2的内存空间,即将tag或dtb首地址赋给__atags_pointer变量

综上所述,在__mmap_switched中,经过一系列的汇编操作,最终会将:

  • 把bootloader传来的r1值, 赋给了C变量: __machine_arch_type
  • 把bootloader传来的r2值, 赋给了C变量: __atags_pointer     // dtb首地址

整个head.S的大致流程如下:

  1. __lookup_processor_type : 使用汇编指令读取CPU ID, 根据该ID找到对应的proc_info_list结构体(里面含有这类CPU的初始化函数、信息)
  2. __vet_atags             : 判断是否存在可用的ATAGS或DTB
  3. __create_page_tables    : 创建页表, 即创建虚拟地址和物理地址的映射关系
  4. __enable_mmu            : 使能MMU, 以后就要使用虚拟地址了
  5. __mmap_switched         : 上述函数里将会调用__mmap_switched
  6. 把bootloader传入的r2参数, 保存到变量__atags_pointer中
  7. 调用C函数start_kernel

总的来说,head.S中所做的操作就是,将r2中保存的tag或dtb的首地址赋给了C变量__atags_pointer。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值