arm-paging_init函数分析

本文详细分析了ARM平台Linux内核的paging_init函数,包括prepare_page_table、bootmem_init、create_mapping等关键步骤。函数主要涉及页表初始化、内存区域映射以及设备映射等操作,为系统的内存管理和地址转换打下基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

arm平台

    start_kernel->

                setup_arch->

                           paging_init

上述代码的1525行函数主要是对所有的mem_type内容进行初始化,1536行是分配个一页内存。1538行调用bootmem_init初始化zone数据。后面会详细分析。

1526行prepare_page_table函数展开如下图

首先1160-1161是对虚拟地址0-MODULES_VADDR地址对应的pmd清空。

1167-1168是对MODULES_VADDR-PAGE_OFFSET虚拟对应的pmd清空,最后对arm_lowmem_limit-VMALLOC_START虚拟地址的页中间目录清空。

Map_lowmem函数是对物理页面进行页表映射设置操作其中会对内核代码做不同的映射。

create_mapping函数实现如下:

上述就是将不同的物理地址区间进行写页表操作,最终写页表的是alloc_init_pud函数,其中页表使用的内存是从memblock里分配的。其中845-870是参数判断等操作,871-878是对传入的起始地址进行PAGE对齐,879-880是获取pgd地址以及结合写入长度计算出结束地址,881-886行是对地址进行写入pgd页全局目录对应的各个页目录以及页表中。

dma_contiguous_remap函数是对dma区重新进行映射,devicemaps_init函数是对设备区域进行映射。

Kmap_init函数实现如下图:

 上图的1326行的宏‘#define FIXADDR_START           0xffc00000UL’

#define PTE_HWTABLE_OFF         (PTE_HWTABLE_PTRS (512)* sizeof(pte_t))

#define PTE_HWTABLE_SIZE        (PTRS_PER_PTE (512)* sizeof(u32))

那么1326行则是调用early_pte_alloc函数去为FIXADDR_START(0xffc00000UL)分配页表

上述的early_pte_alloc第687行判断如果对应的pmd页中间目录不存在则调用early_alloc分配一个页表(注意传入的参数实际上指示的是4K,也就是分配了4k的空间)。接着689行调用__pmd_populate函数去设置页中间目录以及页表。692行是返回addr对应的页表项

下图是__pmd_populate函数实现。

上述可以看到在设置页表的时候给了一个偏移量并不是真正的页表起始地址而是实际分配页表+2K的偏移地址。因为在arm上不存在一些标志位导致需要维护两份页表一份是给linux(保存了一些标志位的)使用,一份给arm硬件使用。139行是刷新tlb将此次修改推送到所有cpu。

综上kmap_init则是针对FIXADDR_START分配页表大概512项pte。

Tcm_init 是初始化tcm这块内存,TCM是一个固定大小的RAM,紧密地耦合至处理器内核,提供与cache相当的性能,相比于cache的优点是,程序代码可以精确地控制什么函数和代码放在哪里。

其中整体内存地址映射如下

 bootmem_init函数:

上述336行find_limits是设置min为物理起始地址,max_low是arm_lowmem_limit,max_high是物理地址最大地址。342行和347行是根据参数决定是否实现,暂时可以看做空函数。

354行是进行zone初始化的真正函数。zone_sizes_init函数会通过free_area_init_node调用free_area_init_core函数去初始化。

zone_sizes_init函数如下图:

上述函数188-205行是申请一些局部变量等操作,其中第201行将zone_size[0]设置为低端内存页数,第203行将zone_size[ZONE_HIGHMEM]统计为高端内存页数。zhole_size保存的是间隙,此次是连续的物理内存所以这里的hole是0。此次为了说明简单没有打开dma配置所以不存在dma_zone。接着调用free_area_init_node函数

free_area_init_node函数:

上述函数的5004-5011行是初始化pgdat变量。5013行calculate_node_totalpages函数会计算整个内存区间的页数保存在pgdat->node_spanned_pages除去缝隙的页数保存在pgdat->node_present_pages,此次说明的条件两者是相等的。5024行调用free_area_init_core函数。

free_area_init_core:

 

上图的4856-4870行是定义一些变量以及初始化等待队列。其中4872-4951是对每个zone进行初始化,其中4876行则是获取对应的zone的页数。4878行是算出真正可用的页数,此次分析的平台则是realsize==size==freesize。4888行则是计算需要的page数据结构所占用的页面数量。此次的值是PAGE_ALIGN(pages * sizeof(struct page)) >> PAGE_SHIFT。其中4889-4900则是从全局可用的页数去除page数据结构所占用的页面。4003-4907则是去除dma保留内存。4909-4910则是初始化全局变量nr_kernel_pages为全zone可用内存。其中4916-4930初始化zone里的数据结构。4931-4935初始化zone结构里的锁资源。4938行是初始化zone->vm_stat和全局变量vm_stat。4940是初始化lruvec链表。4944是针对大页内存的,此次没有开启所以此函数为空。4945行setup_usemap函数是定义了SPARSEMEM才有效,此次没有定义。4946行则是设置了zone的start_pfn,初始化了zone的free_area变量每个order里的每个链表。4949行memmap_init函数则是初始start_pfn到end_pfn之间的page与zone的关系。

memmap_init:

 

 上图4127-4135行则是定义一些局部变量以及获取正在初始化的zone结构。4136-4180则是针对start_pfn到end_pfn里的每个page进行初始化。4148-4149则是初始化page与zone的之间的link。4150则是一些合法性检查。4151则是增加当前的page的引用计数。重置page的mapcount也就是映射计数。4153初始化page的cpuid。4154则是设置page不被swap出去。4169-4173则是初始化可迁移页面的bitmap。4174则是初始化page的lru链表。4177-4178如果不是高端内存则初始化page->virtual地址为page对应的线性地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值