我眼中的Linux设备树(六 memory&chosen节点)
六 memory&chosen节点
根节点那一节我们说过,最简单的设备树也必须包含cpus节点和memory节点。memory节点用来描述硬件内存布局的。如果有多块内存,既可以通过多个memory节点表示,也可以通过一个memory节点的reg属性的多个元素支持。举一个例子,假如某个64位的系统有两块内存,分别是
• RAM: 起始地址 0x0, 长度 0x80000000 (2GB)
• RAM: 起始地址 0x100000000, 长度 0x100000000 (4GB)
对于64位的系统,根节点的#address-cells属性和#size-cells属性都设置成2。一个memory节点的形式如下(还记得前几节说过节点地址必须和reg属性第一个地址相同的事情吧):
memory@0 {
device_type = "memory";
reg = <0x000000000 0x00000000 0x00000000 0x80000000
0x000000001 0x00000000 0x00000001 0x00000000>;
};
两个memory节点的形式如下:
memory@0 {
device_type = "memory";
reg = <0x000000000 0x00000000 0x00000000 0x80000000>;
};
memory@100000000 {
device_type = "memory";
reg = <0x000000001 0x00000000 0x00000001 0x00000000>;
};
chosen节点也位于根节点下,该节点用来给内核传递参数(不代表实际硬件)。对于Linux内核,该节点下最有用的属性是bootargs,该属性的类型是字符串,用来向Linux内核传递cmdline。规范中还定义了stdout-path和stdin-path两个可选的、字符串类型的属性,这两个属性的目的是用来指定标准输入输出设备的,在linux中,这两个属性基本不用。
memory和chosen节点在内核初始化的代码都位于start_kernel()->setup_arch()->setup_machine_fdt()->early_init_dt_scan_nodes()函数中(位于drivers/of/fdt.c),复制代码如下(本节所有代码都来自官方内核4.4-rc7版本):
1078 void __init early_init_dt_scan_nodes(void)
1079 {
1080 /* Retrieve various information from the /chosen node */
1081 of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
1082
1083 /* Initialize {size,address}-cells info */
1084 of_scan_flat_dt(early_init_dt_scan_root, NULL);
1085
1086 /* Setup memory, calling early_init_dt_add_memory_arch */
1087 of_scan_flat_dt(early_init_dt_scan_memory, NULL);
1088 }
of_scan_flat_dt函数扫描整个设备树,实际的动作是在回调函数中完成的。第1081行是对chosen节点操作,该行代码的作用是将节点下的bootargs属性的字符串拷贝到boot_command_line指向的内存中。boot_command_line是内核的一个全局变量,在内核的多处都会用到。第1084行是根据根节点的#address-cells属性和#size-cells属性初始化全局变量dt_root_size_cells和dt_root_addr_cells,还记得前边说过如果没有设置属性的话就用默认值,这些都在early_init_dt_scan_root函数中实现。第1087行是对内存进行初始化,复制early_init_dt_scan_memory部分代码如下:
893 /**
894 * early_init_dt_scan_memory - Look for an parse memory nodes
895 */
896 int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
897 int depth, void *data)
898 {
899 const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
900 const __be32 *reg, *endp;
901 int l;
902
903 /* We are scanning "memory" nodes only */
904 if (type == NULL) {
905 /*
906 * The longtrail doesn't have a device_type on the
907 * /memory node, so look for the node called /memory@0.
908 */
909 if (!IS_ENABLED(CONFIG_PPC32) || depth != 1 || strcmp(uname, "memory@0") != 0)
910 return 0;
911 } else if (strcmp(type, "memory") != 0)
912 return 0;
913
914 reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
915 if (reg == NULL)
916 reg = of_get_flat_dt_prop(node, "reg", &l);
917 if (reg == NULL)
918 return 0;
919
920 endp = reg + (l / sizeof(__be32));
921
922 pr_debug("memory scan node %s, reg size %d,\n", uname, l);
923
924 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
925 u64 base, size;
926
927 base = dt_mem_next_cell(dt_root_addr_cells, ®);
928 size = dt_mem_next_cell(dt_root_size_cells, ®);
929
930 if (size == 0)
931 continue;
932 pr_debug(" - %llx , %llx\n", (unsigned long long)base,
933 (unsigned long long)size);
934
935 early_init_dt_add_memory_arch(base, size);
936 }
937
938 return 0;
939 }
第914行可以看出linux内核不仅支持reg属性,也支持linux,usable-memory属性。对于dt_root_addr_cells和dt_root_size_cells的使用也能看出根节点的#address-cells属性和#size-cells属性都是用来描述内存地址和大小的。得到每块内存的起始地址和大小后,在第935行调用early_init_dt_add_memory_arch函数,复制代码如下:
983 void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
984 {
985 const u64 phys_offset = __pa(PAGE_OFFSET);
986
987 if (!PAGE_ALIGNED(base)) {
988 if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
989 pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
990 base, base + size);
991 return;
992 }
993 size -= PAGE_SIZE - (base & ~PAGE_MASK);
994 base = PAGE_ALIGN(base);
995 }
996 size &= PAGE_MASK;
997
998 if (base > MAX_MEMBLOCK_ADDR) {
999 pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
1000 base, base + size);
1001 return;
1002 }
1003
1004 if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
1005 pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
1006 ((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
1007 size = MAX_MEMBLOCK_ADDR - base + 1;
1008 }
1009
1010 if (base + size < phys_offset) {
1011 pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
1012 base, base + size);
1013 return;
1014 }
1015 if (base < phys_offset) {
1016 pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
1015 if (base < phys_offset) {
1016 pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
1017 base, phys_offset);
1018 size -= phys_offset - base;
1019 base = phys_offset;
1020 }
1021 memblock_add(base, size);
1022 }
从以上代码可以看出内核对地址和大小做了一系列判断后,最后调用memblock_add将内存块加入内核。
我眼中的Linux设备树(六 memory&chosen节点)的更多相关文章
- Linux设备树(六 memory&chosen节点)
六 memory&chosen节点 根节点那一节我们说过,最简单的设备树也必须包含cpus节点和memory节点.memory节点用来描述硬件内存布局的.如果有多块内存,既可以通过多个memo ...
- 我眼中的Linux设备树(五 根节点)
五 根节点一个最简单的设备树必须包含根节点,cpus节点,memory节点.根节点的名字及全路径都是"/",至少需要包含model和compatible两个属性.model属性我们 ...
- 我眼中的Linux设备树(一 概述)
一 概述设备树(Device tree)是一套用来描述硬件属相的规则.ARM Linux采用设备树机制源于2011年3月份Linux创始人Linus Torvalds发的一封邮件,在这封邮件中他提倡A ...
- 我眼中的Linux设备树(二 节点)
二 节点(node)的表示首先说节点的表示方法,除了根节点只用一个斜杠"/"表示外,其他节点的表示形式如"node-name@unit-address".@前边 ...
- 我眼中的Linux设备树(四 中断)
四 中断中断一般包括中断产生设备和中断处理设备.中断控制器负责处理中断,每一个中断都有对应的中断号及触发条件.中断产生设备可能有多个中断源,有时多个中断源对应中断控制器中的一个中断,这种情况中断产生设 ...
- 我眼中的Linux设备树(三 属性)
三 属性(property)device_type = "memory"就是一个属性,等号前边是属性,后边是值.节点是一个逻辑上相对独立的实体,属性是用来描述节点特性的,根据需要一 ...
- linux设备树语法
设备树语法及绑定 概述 Device Tree是一种用来描述硬件的数据结构,类似板级描述语言,起源于OpenFirmware(OF). 就ARM平台来说,设备树文件存放在arch/arm/boot/d ...
- Linux设备树(五 根节点)
五 根节点 一个最简单的设备树必须包含根节点,cpus节点,memory节点.根节点的名字及全路径都是“/”,至少需要包含model和compatible两个属性.model属性我们在属性那节已经说过 ...
- linux 设备树【转】
转自:http://blog.csdn.net/chenqianleo/article/details/77779439 [-] linux 设备树 为什么要使用设备树Device Tree 设备树的 ...
随机推荐
- Docker 第一篇 认识Docker 的作用好处
Docker 第一篇 认识Docker 的作用好处 (1)什么是Docker (2)Docker 优势劣势 Docker是去年开始关注并学习的,因为项目用到了AspnetCore 了解了之后总感觉会用 ...
- fireBug引入JQuery,方便书写jq调试代码
在控制台执行下段代码,等到网络中加载完成后,即可正常运行jq代码.也可以根据需要进行修改引入其他js代码. javascript:(function(url) { var s = document.c ...
- 常见压缩格式分析,及 Linux 下的压缩相关指令
可先浏览加粗部分 一.常见压缩档 *.zip | zip 程式壓縮打包的檔案: (很常见,但是因为不包含文件名编码信息,跨平台可能会乱码) *.rar | winrar 程序压缩打包的档案:(在win ...
- python笔记六(函数的参数、返回值)
一 调用函数 在写函数之前,我们先尝试调用现有的函数 >>> abs(-9) 9 除此之外,还有我们之前使用的len()等.可以用于数据类型转换的 int() float() str ...
- JAVA中抽象类的使用
抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象.抽象类体现的就是一种模板模式的设计,抽象父类可以只定义需要使用的某些方法,把不能实现的某些部分抽象成抽象方法,留给其子类去实现.具体来说,抽 ...
- 码农代理免费代理ip端口字段js加密破解
起因 之前挖过爬取免费代理ip的坑,一个比较帅的同事热心发我有免费代理ip的网站,遂研究了下:https://proxy.coderbusy.com/. 解密 因为之前爬过类似的网站有了些经验,大概知 ...
- 学习在.NET Core中使用RabbitMQ进行消息传递之持久化(二)
前言 上一节我们简单介绍了RabbitMQ和在安装后启动所出现的问题,本节我们开始正式进入RabbitMQ的学习,对于基本概念请从官网或者其他前辈博客上查阅,我这里不介绍基础性东西,只会简单提一下,请 ...
- SpringMVC常用配置(二),最简洁的配置实现文件上传
Spring.SpringMVC持续介绍中,基础配置前面已经介绍了很多,如果小伙伴们还不熟悉可以参考这几篇文章: 1.Spring基础配置 2.Spring常用配置 3.Spring常用配置(二) 4 ...
- [Vim]新建python文件自动添加python header
使用vim脚本来实现的,使用了模板,几行代码就能实现很实用. ~/.vimrc 中的代码 "auto add pyhton header --start autocmd BufNewFile ...
- python+OpenCV 特征点检测
1.Harris角点检测 Harris角点检测算法是一个极为简单的角点检测算法,该算法在1988年就被发明了,算法的主要思想是如果像素周围显示存在多于一个方向的边,我们认为该点为兴趣点.基本原理是根据 ...