Linux内存管理(1)物理内存初始化

问题思考

  1. 系统启动时,arm-linux内核怎么系统系统到底有多大的内存空间
  2. 在32bit的linux内核中,用户空间和内核空间的比例通常是3:1,可以修改成2:2么
  3. 物理内存页面如何添加到伙伴系统中,是一页一页添加,还是以2的几次幂来加入呢

 

内存简介

从硬件的角度来看内存。内存是什么,内存是ram(随机存储器,Random access memory),是可以直接与cpu交换数据的内部寄存器。现在大部分都使用ddr来作为内存,ddr包括DDR3L、DDR4L、LPDDR3/4。ddr的初始化一般是在BIOS或者boot loader中,BIOS或者boot loader吧ddr的大小传递给linux内核,因此从linux内核来看ddr其实就是一段物理内存空间。

 

内存管理结构

内存管理是一个很复杂的系统,设计的内容很多。如果用分层来描述,内存空间可以分成三个层次,分别是用户空间、内核空间、硬件层。如下图所示:

  1. 用户空间层:可以理解为linux内核内存管理为用户空间暴露的系统调用接口,例如brk、mmap等系统调用。通常libc库会封装成常见的c语言函数,如malloc和mmap等
  2. 内核空间层:内核空间的模块非常丰富,具体的内存实现原理都是在内核层面的。用户空间和内核空间的接口是系统调用,因此内核空间层首先需要处理这些内存管理相关的系统调用,比如sys_brk等。接下来包括vma管理、缺页中断管理、匿名页面、page cache、页面回收、反向映射、slab分配器、页表管理等模块了
  3. 硬件层:包括处理器的MMU、TLB和cache,以及板载的物理内存,比如ddr

 

内存大小

在ARM linux中,各种设备的相关属性描述都在用DTS方式来呈现。,比如arm vexpress平台,该文件中定义了内存的起始地址为0x60000000,大小为0x40000000,即1GB大小的内存空间。

比如arch\arm\boot\dts\vexpress-v2p-ca9.dts

memory@60000000 {
	device_type = "memory";
	reg = <0x60000000 0x40000000>;
};

内核在启动过程中会解析这个dts文件,然后得到内存的基地址和大小,然后把这些变量加到memblock中,使用函数early_init_dt_add_memory_arch-->memblock_add将内存块信息加到memblock中,memblock是系统启动阶段的内存分配器,系统启动之后有伙伴系统接管内存分配工作。

解析函数调用流程为:start_kernel-->setup_arch-->setup_machine_fdt-->early_init_dt_scan_nodes-->early_init_dt_scan_memory-->early_init_dt_add_memory_arch-->memblock_add

解析函数如下所示:

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);
    //device_type = "memory"
	const __be32 *reg, *endp;
	int l;

	/* We are scanning "memory" nodes only */
	if (type == NULL) {
		/*
		 * The longtrail doesn't have a device_type on the
		 * /memory node, so look for the node called /memory@0.
		 */
		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);
    //reg = <0x60000000 0x40000000>
	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);//0x60000000
		size = dt_mem_next_cell(dt_root_size_cells, &reg);//0x40000000

		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);//base和size数据有效性校验
	}

	return 0;
}

 

物理内存映射

物理内存映射,其实就是简历内存页表的过程,因为内核中直接使用的都是内存,所以需要创建页表来映射物理内存。初始化内核页表主要在函数mam_lowmem()函数中。在影射页表之前,需要把页表的页表项清零,主要在prepare_page_table函数中实现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值