[2]MM之zone、zone_list初始化

在对OS部分物理内存进行了识别标记后,系统将进入到zone初始化阶段。

[zone的由来]

​ 由于硬件的限制,内核不能对所有的页一视同仁。有些页位于内存中特定的物理地址上,所以不能将其用于一些特定的任务。由于存在这种限制,所以内核把页划分为不同的区(zone)。内核使用区对具有相似特性的页进行分组。

​ 1、UMA内存模型结构

​ 嵌入式设备所使用的平台内存结构均为UMA模型,因此笔者也仅是对此模型的内存管理进行学习分析。笔者所用平台为某一特定四核arm64 CPU、DDR最大支持为8GB、OS内存划分得2GB。依据UMA模型的特性以及所用平台内核的配置,该平台对应的内存组织结构如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hl4sBCzs-1662345187316)(C:/Users/gaoyuke/AppData/Roaming/Typora/typora-user-images/image-20220902090534316.png)]
​ 从上图可见,内存管理系统是一个三级结构:node、zone和page。

层次描述
存储节点(Node)在UMA模型中始终只要一个节点
管理区(Zone)每个物理内存节点node被划分为多个内存管理区域, 用于表示不同范围的内存, 内核可以使用不同的映射方式 映射物理内存
页面(Page)内存被细分为多个页面帧, 页面是最基本的页面分配的单位

2、ZONE的类型及特点

Linux内核代码中定义了zone_type类型:

enum zone_type {

\#ifdef CONFIG_ZONE_DMA

​    ZONE_DMA,

\#endif

\#ifdef CONFIG_ZONE_DMA32

​    ZONE_DMA32,

\#endif

​    ZONE_NORMAL,

\#ifdef CONFIG_HIGHMEM

​    ZONE_HIGHMEM,

\#endif

​    ZONE_MOVABLE,

\#ifdef CONFIG_ZONE_DEVICE

​    ZONE_DEVICE,

\#endif

​    __MAX_NR_ZONES

};

​ 其分别对应不同的含义,具体描述如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PJ9uFo1r-1662345187317)(C:/Users/gaoyuke/AppData/Roaming/Typora/typora-user-images/image-20220902085617214.png)]
​ 具体所用arm64平台OS内存是在DMA/DMA32区域还是NORMAL区域,要看内核配置是否开启了CONFIG_ZONE_DMA/CONFIG_ZONE_DMA32选项。笔者所用config配置仅使能了ZONE_DMA32,因此当OS内存在4GB以内时,所有内存皆在ZONE_DMA32区域;当OS内存大于4GB时,04GB内存在ZONE_DMA32区域,4GBmax内存在ZONE_NORMAL区域。

3、ZONE的初始化

数据结构,仅是摘取了内存结构相关的要素
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M29jnL6X-1662345187317)(C:/Users/gaoyuke/AppData/Roaming/Typora/typora-user-images/image-20220905103041803.png)]
大致流程

start_kernel
|--->setup_arch
|--->|--->bootmem_init
|--->|--->|--->arm64_memory_present  //memblock.memory中物理内存段对应的section初始化;段大小为64MB
|--->|--->|--->zone_sizes_init       //不同zone类型所管理的内存大小初始化
|--->|--->|--->|--->free_area_init_node
|--->|--->|--->|--->|--->calculate_node_totalpages  //不同ZONE——type管理内存大小以及去掉内存黑洞(标记有no-map)后大小
|--->|--->|--->|--->|--->free_area_init_core
|--->|--->|--->|--->|--->|--->init_currently_empty_zone
|--->|--->|--->|--->|--->|--->|--->zone_init_free_lists   //初始化free_list链表
|--->|--->|--->|--->|--->|--->memmap_init  以pageblock为单位将pfn对应的page迁移类型置为movable
static void __init zone_sizes_init(unsigned long min, unsigned long max)
{
	struct memblock_region *reg;
	unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES];
	unsigned long max_dma = min;

	memset(zone_size, 0, sizeof(zone_size));
	
	/* 4GB maximum for 32-bit only capable devices */
#ifdef CONFIG_ZONE_DMA32
	max_dma = PFN_DOWN(arm64_dma_phys_limit);
	zone_size[ZONE_DMA32] = max_dma - min;
#endif
	zone_size[ZONE_NORMAL] = max - max_dma;
    
	memcpy(zhole_size, zone_size, sizeof(zhole_size));
	
	free_area_init_node(0, zone_size, min, zhole_size);
}

zonelist 与 pcp 的初始化

start_kernel
|--->build_all_zonelists(NULL)
|--->|--->build_all_zonelists_init()
|--->|--->|--->__build_all_zonelists(NULL)
|--->|--->|--->|--->build_zonelists(pgdat)
|--->|--->|--->|--->|--->zonerefs = pgdat->node_zonelists[ZONELIST_FALLBACK]._zonerefs
|--->|--->|--->|--->|--->nr_zones = build_zonerefs_node(pgdat, zonerefs)
|--->|--->|--->|--->|--->|--->zone = pgdat->node_zones + zone_type
|--->|--->|--->|--->|--->|--->zoneref->zone = zone
|--->|--->|--->|--->|--->|--->zoneref->zone_idx = zone_idx(zone)
|--->|--->|--->setup_pageset(&per_cpu(boot_pageset, cpu), 0)  //初始化pcp,pcp在内存分配中专用于order=0的处理
|--->|--->|--->|--->pageset_init(p)
|--->|--->|--->|--->|--->for (migratetype = 0; migratetype < MIGRATE_PCPTYPES; migratetype++)
|--->|--->|--->|--->|--->INIT_LIST_HEAD(&pcp->lists[migratetype]);
|--->|--->|--->|--->pageset_set_batch(p, batch)

水平有限,如果有错误,请帮忙指出提醒。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值