linux kernel物理内存概述(三)

目录

一、物理内存空间划分

二、物理内存初始化

查看当前页面分配状态

三、页块

页面如何添加到伙伴系统中?


一、物理内存空间划分

  • 32位系统 4GB 用户空间和内核空间划分 3:1

  • ARM64架构处理器虚拟地址空间划分方式;

  • 内核中使用PAGE_OFFSET宏计算 内核线性映射中 **虚拟地址和物理地址的转换 **

    #define VA_BITS (CONFIG_ARM64_VA_BITS)
    #define VA_START (UL(0×ffffffffffffffff) - \
    (UL(1) << VABITS)+1)
    #define VA_OFFSET (UL(0×ffffffffffffffff) -\
    (UL (1) << (VA_BITS - 1)) +1)
  • CONFIG_ARM64_VA_BITS设置48,那么PAGE_OFFSET的值为0xFFFF 8000 0000 0000

  • 内核中计算线性映射的物理地址和虚拟地址的转换关系 线性映射的物理地址 = vaddr - PAGE_OFFSET + PHYS_OFFSET

  • 内核常用的宏 __pa()和__va()

  • __phys_to_virt()用于根据计算物理地址 计算线性映射的虚拟地址

  • __virt_to_phys_nodebug()根据虚拟地址计算物理地址。在arm64内核中,内核空间虚拟地址分为1,线性映射区域;2,vmalloc区域,内核会映射到vmalloc区域

  • __is_lm_address 用于判断虚拟地址是否为线性映射的虚拟地址

二、物理内存初始化

在内核启动时,DDR大小,内存起始地址和内核空间内存布局,以及映射关系。物理内存要添加到 伙伴系统中 伙伴系统是内核中内存管理一种方法,在用户提出申请时,分配一个大小合适的内存块给用户。内存块的大小2的order次幂个页面;

  • order最大值是MAX_ORDER 通常是11,就是把所有空闲页面分成11个内存块链表,每个内存块链表分别有1,2,4,8, 1024个连续页面。 zone结构体中有free_area数组,大小是MAX_ORDER.free_area数据结构中包含了MIGRATE_TYPES(不可移动、可回收、可移动页面)个链表

查看当前页面分配状态

# cat /proc/pagetypeinfo 
Page block order: 9
Pages per block:  512

Free pages count per migrate type at order       0      1      2      3      4      5      6      7      8      9     10 
Node    0, zone      DMA, type    Unmovable      0      0      0      0      0      0      0      1      0      0      0 
Node    0, zone      DMA, type      Movable      0      0      0      0      0      0      0      0      0      1      3 
Node    0, zone      DMA, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone      DMA, type   HighAtomic      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone      DMA, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type    Unmovable    200    200    296    190    130     61     47     13      5      8      5 
Node    0, zone    DMA32, type      Movable   1990    153     26     14      0      1      1      0      0      4      4 
Node    0, zone    DMA32, type  Reclaimable   1009    246    171     12     91     28      4      0      0      0      0 
Node    0, zone    DMA32, type   HighAtomic      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type    Unmovable    468    398    242     80     54     16      2      2      0      0      0 
Node    0, zone   Normal, type      Movable      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type  Reclaimable    174     55     45     12      0      0      0      0      0      0      0 
Node    0, zone   Normal, type   HighAtomic     15     10      3      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 

Number of blocks type     Unmovable      Movable  Reclaimable   HighAtomic      Isolate 
Node 0, zone      DMA            1            7            0            0            0 
Node 0, zone    DMA32          434         1037           57            0            0 
Node 0, zone   Normal          149          331           31            1            0 

 从上可以看出

  • Node 节点有1个
  • Node 划分为3个zone Normal DMA32 DMA
  • 伙伴系统的类型 Isolate,Reclaimable,Movable,Unmovable,HighAtomic,
  • 伙伴系统的阶数 0~10
  • 大部分的页面是DMA32的Movable

三、页块

  • 内核中,一个页块大小通常是2(MAX_ORDER-1)个页面
  • 每个页块有迁移属性,zone->pageblock_flags指向其内存空间;
  • 迁移类型内存空间大小通过usemap_size函数来计算 zone初始化函数free_area_init_core会调用setup_usemap()函数计算大小,并分配内存;
static void __ref setup_usemap(struct pglist_data *pgdat,
				struct zone *zone,
				unsigned long zone_start_pfn,
				unsigned long zonesize)
{
	unsigned long usemapsize = usemap_size(zone_start_pfn, zonesize);
	if (usemapsize) {
		zone->pageblock_flags =
			memblock_alloc_node(usemapsize, SMP_CACHE_BYTES,
					    pgdat->node_id);
	}
}
/*
 * Calculate the size of the zone->blockflags rounded to an unsigned long
 */
static unsigned long __init usemap_size(unsigned long zone_start_pfn, unsigned long zonesize)
{
	unsigned long usemapsize;
	zonesize += zone_start_pfn & (pageblock_nr_pages-1);
	usemapsize = roundup(zonesize, pageblock_nr_pages);
	usemapsize = usemapsize >> pageblock_order;
	usemapsize *= NR_PAGEBLOCK_BITS;
	usemapsize = roundup(usemapsize, 8 * sizeof(unsigned long));
	return usemapsize / 8;
}

  • 首先,通过四舍五入确保zonesize是pageblock_order的倍数。
  • 然后每个页面块使用1个NR_PAGEBLOCK_BITS值的比特,
  • 最后将现在的比特四舍五入到最接近的long
  • memblock_alloc_node 分配内存,设置类型,并赋值给pageblock_flags

页面如何添加到伙伴系统中?

<start_kernel->mm_init->mem_init->free_all_bootmem->free_low_memory_core_eearly> free_low_memory_core_eearly函数,通过for_each_free_mem_range遍历所有内存块,找出内存块的起始地址和结束地址。

 函数调用关系

static unsigned long __init free_low_memory_core_early(void)
{
	for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end,
				NULL)
		count += __free_memory_core(start, end);
	return count;
}
static unsigned long __init __free_memory_core(phys_addr_t start,
				 phys_addr_t end)
{
	unsigned long start_pfn = PFN_UP(start);
	unsigned long end_pfn = min_t(unsigned long,
				      PFN_DOWN(end), max_low_pfn);
	if (start_pfn >= end_pfn)
		return 0;
	__free_pages_memory(start_pfn, end_pfn);
	return end_pfn - start_pfn;
}
static void __init __free_pages_memory(unsigned long start, unsigned long end)
{
	int order;

	while (start < end) {
		order = min(MAX_ORDER - 1UL, __ffs(start));

		while (start + (1UL << order) > end)
			order--;

		memblock_free_pages(pfn_to_page(start), start, order);

		start += (1UL << order);
	}
}
void __init memblock_free_pages(struct page *page, unsigned long pfn,
							unsigned int order)
{
	__free_pages_core(page, order);
}
void __free_pages_core(struct page *page, unsigned int order)
{
    ...
	__free_pages_ok(page, order, FPI_TO_TAIL);
}
static void __free_pages_ok(struct page *page, unsigned int order,
			    fpi_t fpi_flags)
{

	free_one_page(page_zone(page), page, pfn, order, migratetype,
		      fpi_flags);
}
static void free_one_page(struct zone *zone,
				struct page *page, unsigned long pfn,
				unsigned int order,
				int migratetype, fpi_t fpi_flags)
{
	__free_one_page(page, pfn, zone, order, migratetype, fpi_flags);
}
  • 参数start和end时起始与终止页帧号,while循环遍历[start,end],步长取MAX_ORDER-1和__ffs(start)中较小值
  • 假设start起始地址0x35300,该地址以0x100对其,通过__ffs(start)计算出合适的order值为8,(2^8=0x100)。此起始地址适合创建一个2^8个页面,并添加到order为8的伙伴系统中;
  • 得到order 最后调用__free_pages_core 将内存添加到伙伴系统中

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值