搜索
您的当前位置:首页正文

物理内存映射

来源:步旅网

问题1:在系统启动是,arm linux内核如何知道系统中有多大的内存空间?

        物理内存大小定义在设备树的memory节点中,系统启动时会通过dtb解析memory节点,从而获得内存大小。

内存大小定义

start_kernel->setup_arch->setup_machine_fdt->early_init_dt_scan_nodes->of_scan_flat_dt->early_init_dt_scan_memory

在函数early_init_dt_scan_memory会解析memory节点

/**
 * early_init_dt_scan_memory - Look for an parse memory nodes
 */
int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
				     int depth, void *data)
{
	..........................
	while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
		u64 base, size;
		..............................................
		printk(KERN_EMERG "base %llx, size %llx\n", base, size);
		early_init_dt_add_memory_arch(base, size);
	}
	return 0;
}

sudo qemu-system-arm -M vexpress-a9 -m 1024M。如果-m 512M

则会输出base 60000000, size 20000000(512M)

感觉是二者取较小值

 物理内存映射

void __init paging_init(const struct machine_desc *mdesc)
{
	void *zero_page;
	printk(KERN_EMERG "\r\npaging_init begin\n");
	/* 给静态全局变量mem_types赋值 */
	build_mem_type_table();
	prepare_page_table();//将页表项清零
	map_lowmem();//初始化页表,真正创建页表,重新建立从物理地址起始点到high_mem的起始点的一一映射
	/* 建立DMA映射表 */
	dma_contiguous_remap();
	/* 为设备IO空间和中断向量表创建页表,并刷新TLB和缓存 */
	devicemaps_init(mdesc);
	/* 进行永久内存映射的初始化,存储在pkmap_page_table中 */
	kmap_init();
	/* TCM初始化,TCM是一个固定大小的RAM,紧密地耦合至处理器内核,提供与cache相当的性能 */
	tcm_init();

	top_pmd = pmd_off_k(0xffff0000);

	/* allocate the zero page. */
	zero_page = early_alloc(PAGE_SIZE);
	/* bootmem_init初始化内存管理 */
	bootmem_init();

	/* 分配一个0页,该页用于写时复制机制。 */
	empty_zero_page = virt_to_page(zero_page);
	__flush_dcache_page(NULL, empty_zero_page);
}

prepare_page_table:把页表项清零

static inline void prepare_page_table(void)
{
	unsigned long addr;
	phys_addr_t end;

	/*
	 * Clear out all the mappings below the kernel image.
	 */
	for (addr = 0; addr < MODULES_VADDR; addr += PMD_SIZE)
		pmd_clear(pmd_off_k(addr));

#ifdef CONFIG_XIP_KERNEL
	/* The XIP kernel is mapped in the module area -- skip over it */
	addr = ((unsigned long)_etext + PMD_SIZE - 1) & PMD_MASK;
#endif
	for ( ; addr < PAGE_OFFSET; addr += PMD_SIZE)
		pmd_clear(pmd_off_k(addr));

	/*
	 * Find the end of the first block of lowmem.
	 */
	end = memblock.memory.regions[0].base + memblock.memory.regions[0].size;
	if (end >= arm_lowmem_limit)
		end = arm_lowmem_limit;

	/*
	 * Clear out all the kernel space mappings, except for the first
	 * memory bank, up to the vmalloc region.
	 */
	for (addr = __phys_to_virt(end);
	     addr < VMALLOC_START; addr += PMD_SIZE)
		pmd_clear(pmd_off_k(addr));
	printk(KERN_EMERG "\r\n MODULES_VADDR %lx, PAGE_OFFSET %lx, VMALLOC_START %lx\n", \
			(unsigned long)MODULES_VADDR, (unsigned long)PAGE_OFFSET, (unsigned long)VMALLOC_START);
}

0x0--MODULES_VADDR ; 

MODULES_VADDR--PAGE_OFFSET; 

arm_lowmem_limit--VMALLOC_START

arm_lowmem_limit a0000000

 map_lowmem:初始化页表

_stext和__init_end分别是内核代码段开始和结束

static void __init map_lowmem(void)
{
	struct memblock_region *reg;
	unsigned long kernel_x_start = round_down(__pa(_stext), SECTION_SIZE);
	unsigned long kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE);
	printk(KERN_EMERG "\r\n arm_lowmem_limit %lx", arm_lowmem_limit);
	printk(KERN_EMERG "\r\n kernel_x_start %lx,kernel_x_end %lx", kernel_x_start, kernel_x_end);
	/* Map all the lowmem memory banks. */
	for_each_memblock(memory, reg) {
		phys_addr_t start = reg->base;
		phys_addr_t end = start + reg->size;
		struct map_desc map;

		if (end > arm_lowmem_limit)
			end = arm_lowmem_limit;
		if (start >= end)
			break;
		printk(KERN_EMERG "\r\n start %lx, end %lx, size %lx\n", start, end, reg->size);
		if (end < kernel_x_start || start >= kernel_x_end) {
            /* 将物理地址转为物理page number, 这里是4k为一页 */
			map.pfn = __phys_to_pfn(start);
			map.virtual = __phys_to_virt(start);
			map.length = end - start;
			map.type = MT_MEMORY_RWX;

            /* create_mapping进行线性映射 */
			create_mapping(&map);
		} else {
			/* This better cover the entire kernel */
			if (start < kernel_x_start) {
				map.pfn = __phys_to_pfn(start);
				map.virtual = __phys_to_virt(start);
				map.length = kernel_x_start - start;
				map.type = MT_MEMORY_RW;

				create_mapping(&map);
			}
            /* 映射kernel image区域 */
			map.pfn = __phys_to_pfn(kernel_x_start);
			map.virtual = __phys_to_virt(kernel_x_start);
			map.length = kernel_x_end - kernel_x_start;
			map.type = MT_MEMORY_RWX;

			create_mapping(&map);
            /* 书上说映射低端内存,为什么是低端内存呢 */
			if (kernel_x_end < end) {
				map.pfn = __phys_to_pfn(kernel_x_end);
				map.virtual = __phys_to_virt(kernel_x_end);
				map.length = end - kernel_x_end;
				map.type = MT_MEMORY_RW;

				create_mapping(&map);
			}
		}
	}
}
#define for_each_memblock(memblock_type, region)					\
	for (region = memblock.memblock_type.regions;				\
	     region < (memblock.memblock_type.regions + memblock.memblock_type.cnt);	\
	     region++)

可以看到这里的 map_lowmem函数里for_each_memblock(memory, reg)就是在使用之前memblock子系统里面的动态内存部分。在关于memblock子系统部分,关于memory_type为memory,即动态内存的部分,也只加入了一个区域,即dts里面定义的memory节点。因此这里也只循环了一次

static void __init map_lowmem(void)
{
	....................
		if (end < kernel_x_start || start >= kernel_x_end) {
           /*不走这里*/.................
		} else {
			/* This better cover the entire kernel */
			if (start < kernel_x_start) {
                /* 也不走这里 */................................
			}
            /* 映射kernel image区域 */
			map.pfn = __phys_to_pfn(kernel_x_start);
			map.virtual = __phys_to_virt(kernel_x_start);
			map.length = kernel_x_end - kernel_x_start;
			map.type = MT_MEMORY_RWX;

			create_mapping(&map);
            /*
             书上说映射低端内存,为什么是低端内存呢?
             因为这部分内存是进行线性映射的,因此属于低端内存(zone_dma & zone_normal )
             */
			if (kernel_x_end < end) {
				map.pfn = __phys_to_pfn(kernel_x_end);
				map.virtual = __phys_to_virt(kernel_x_end);
				map.length = end - kernel_x_end;
				map.type = MT_MEMORY_RW;

				create_mapping(&map);
			}
		}
	}
}

map_lowmem:

如上面代码所示,该函数会对两个区域进行映射(主要是两个区域的属性不一样)

这里感觉和书上写的不一样。那这1G的物理内存全部都拿去做线性映射了,没有所谓的高端内存

下图里面的lowmem刚好也是1024M

书上的arm_lowmem_limit=0x8f800000,意味着低端内存大小为0x8f800000-0x60000000=760M

那高端内存还有1024-760 = 264M.

那至此低端内存的全部都和页表建立了对应的映射关系。那高端内存呢?这个感觉是用到了在建立映射关系吧,比较这种映射关系不是固定的

因篇幅问题不能全部显示,请点此查看更多更全内容

Top