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节点用来描述硬件内存布局的.如果有多块内存,既可以通过多个memor ...
- 我眼中的Linux设备树(五 根节点)
五 根节点一个最简单的设备树必须包含根节点,cpus节点,memory节点.根节点的名字及全路径都是"/",至少需要包含model和compatible两个属性.model属性我们 ...
- Linux设备树(五 根节点)
五 根节点 一个最简单的设备树必须包含根节点,cpus节点,memory节点.根节点的名字及全路径都是“/”,至少需要包含model和compatible两个属性.model属性我们在属性那节已经说过 ...
- linux 设备树【转】
转自:http://blog.csdn.net/chenqianleo/article/details/77779439 [-] linux 设备树 为什么要使用设备树Device Tree 设备树的 ...
- linux设备树语法
设备树语法及绑定 概述 Device Tree是一种用来描述硬件的数据结构,类似板级描述语言,起源于OpenFirmware(OF). 就ARM平台来说,设备树文件存放在arch/arm/boot/d ...
- 【转载】Linux设备树(Device Tree)机制
转:Linux设备树(Device Tree)机制 目录 1. 设备树(Device Tree)基本概念及作用2. 设备树的组成和使用 2.1. DTS和DTSI 2.2. DTC 2.3. DT ...
- Linux设备树语法详解
概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写.引入了设备树之后,驱动代 ...
- Linux设备树语法详解【转】
转自:http://www.cnblogs.com/xiaojiang1025/p/6131381.html 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备 ...
- 宋牧春: Linux设备树文件结构与解析深度分析(2) 【转】
转自:https://mp.weixin.qq.com/s/WPZSElF3OQPMGqdoldm07A 作者简介 宋牧春,linux内核爱好者,喜欢阅读各种开源代码(uboot.linux.ucos ...
随机推荐
- JavaScript(二)数据类型(一)
计算机程序的运行需要对值进行操作,在编程语言中值的类型被称作数据类型,编程语言最基本的特性就是能够支持多种数据类型.当程序需要将值保存起来以备将来使用时,便将其赋值给一个变量.变量是一个值的符号名称, ...
- c/c++ 网络编程 UDP 改变网卡的硬件地址
网络编程 UDP 改变网卡的硬件地址 在程序里动态改变网卡的硬件地址 1,取得网卡的硬件地址 #include <stdio.h> #include <string.h> #i ...
- 一天一个Linux命令--find
文件查找:(以find为主) which:查找命令字所在的位置 locate:模糊匹配(只要包含关键字的文件都查找出来) 不是实时的,基于数据库查找, updatedb升级loca ...
- Linux、CentOS7下JDK环境配置
Linux版本 1.上传JDK包至指定目录,并解压 tar -xzvf jdk-7u80-linux-x64.tar.gz 2.配置JDK环境变量 打开/etc/profile配置文件 vim /et ...
- [原创]GDB调试指南-断点设置
前言 上篇<GDB调试指南-启动调试>我们讲到了GDB启动调试的多种方式,分别应用于多种场景.今天我们来介绍一下断点设置的多种方式. 为何要设置断点 在介绍之前,我们首先需要了解,为什么需 ...
- c#语法学习
自动属性.隐试类型.命名参数和自动初始化器. note:这里说的这些,是语法糖.按照一定的格式写,部分代码编译器帮我们实现了, 1.自动属性:自动属性是非常有用的语法糖,帮我我们做了两件事:1.自动帮 ...
- MySQL之ORM框架SQLAlchemy
一 介绍 SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取 ...
- UVALive - 3523 - Knights of the Round Table
Problem UVALive - 3523 - Knights of the Round Table Time Limit: 4500 mSec Problem Description Input ...
- vim美化基本配置
在home目录中创建一个 .vimrc文件 vim ~/.vimrc 文件基本配置 " 设置当文件被改动时自动载入 set autoread " quickfix模式 autocm ...
- 【Codeforces 1000F】One Occurrence
题意:给一个序列,每次查询某个区间内一个只出现一次的数. 思路:线段树. 首先我们看只出现一次的本质是什么. 如果一个数\(x\)在\((l,r)\)中只出现了一次,那么它在其中第一次出现位置为\ ...