【linux kernel】linux内核如何获取当前运行环境下的内存大小

linux内核如何获取当前运行平台下的内存大小

注1:本文属于《linux内存管理》模块系列的文章

注2:本文中所有源码出自linux内核版本:4.1.15

注3:本文内容基于ARM架构

在支持设备树(DTS)的linux版本下,可以通过设备树将重要参数传递给linux内核。查看一下linux内核源码的设备树目录,如下图所示(/arch/arm/boot/dts):
在这里插入图片描述

在该目录下,后缀为dtsi的是设备树头文件,后缀为dts是具体的设备树文件(其中dts文件将使用#include "xxx"类似语法包含dtsi设备树头文件)。其中大多都是关于具体芯片、厂商的设备树文件。本文以imx6sll-evk.dts的板卡级设备树描述文件为例,在该文件中用于描述具体硬件板卡内存大小的设备节点如下所示:

	memory@80000000 {
		reg = <0x80000000 0x80000000>;
	};

可见,该内存起始地址是:0x80000000,内存大小是:0x80000000(即2G大小的内存空间)。


这里以ARM架构为例,在linux内核启动过程中,需要对设备树文件进行解析,需要解析出的参数很多,其中linux内核使用early_init_dt_scan_memory()函数查找并解析memory节点。如下代码:

int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
				     int depth, void *data)
{
	const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
	const __be32 *reg, *endp;
	int l;

	if (type == NULL) {
		if (!IS_ENABLED(CONFIG_PPC32) || depth != 1 || strcmp(uname, "memory@0") != 0)
			return 0;
	} else if (strcmp(type, "memory") != 0)
		return 0;

	reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
	if (reg == NULL)
		reg = of_get_flat_dt_prop(node, "reg", &l);
	if (reg == NULL)
		return 0;

	endp = reg + (l / sizeof(__be32));

	pr_debug("memory scan node %s, reg size %d,\n", uname, l);

	while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
		u64 base, size;

		base = dt_mem_next_cell(dt_root_addr_cells, &reg);
		size = dt_mem_next_cell(dt_root_size_cells, &reg);

		if (size == 0)
			continue;
		pr_debug(" - %llx ,  %llx\n", (unsigned long long)base,
		    (unsigned long long)size);

		early_init_dt_add_memory_arch(base, size);
	}

	return 0;
}

上述第8-12行判断是否是memory内存设备树节点,如果不是,函数则返回,否则将继续后续的解析操作。

上述14 - 18行功能是解析出memory设备树节点的字符串信息。

第24 - 36行while循环代码功能是:通过解析出的字符串信息reg获取内存的开始地址base和内存大小size。然后调用early_init_dt_add_memory_arch()函数,当该函数运行完成后,base和size的信息就被添加到memblock子系统去了。early_init_dt_add_memory_arch函数定义(/drivers/of/fdt.c):


void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
{
	const u64 phys_offset = __pa(PAGE_OFFSET);

	if (!PAGE_ALIGNED(base)) {
		if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
			pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
				base, base + size);
			return;
		}
		size -= PAGE_SIZE - (base & ~PAGE_MASK);
		base = PAGE_ALIGN(base);
	}
	size &= PAGE_MASK;

	if (base > MAX_MEMBLOCK_ADDR) {
		pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
				base, base + size);
		return;
	}

	if (base + size - 1 > MAX_MEMBLOCK_ADDR) {
		pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
				((u64)MAX_MEMBLOCK_ADDR) + 1, base + size);
		size = MAX_MEMBLOCK_ADDR - base + 1;
	}

	if (base + size < phys_offset) {
		pr_warning("Ignoring memory block 0x%llx - 0x%llx\n",
			   base, base + size);
		return;
	}
	if (base < phys_offset) {
		pr_warning("Ignoring memory range 0x%llx - 0x%llx\n",
			   base, phys_offset);
		size -= phys_offset - base;
		base = phys_offset;
	}
    //将base和size添加到memblock子系统
	memblock_add(base, size);
}

early_init_dt_scan_memory()的调用关系:
在这里插入图片描述


搜索关注【嵌入式小生】wx公众号获取更多精彩内容>>>>
请添加图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值