linux系统启动时的内存操作(一)

 

1。pg0的位置和尺寸

当系统刚刚启动时,在分页功能未打开前,线性地址和物理地址是一一对应的。刚开启分页功能时,pg0的内存地址是 在编译内核时定义好的,见arch\i386\kernel\vmlinux.lsd.S,大小为4096字节,启始地址紧跟内核在内存中物理地址。由于 内核保护模式代码启始位置为0x100000,所以pg0地址=0x100000+内核保护模式代码尺寸。

对pg0的操作主要是开启分页机制时填写页面描述表信息,上一节在第一次页寻址设置中已经详细介绍。

2。内存位图的内存操作

内存位图是系统设置区域和页面管理前的内存使用状态表。

2.1内存位图的位置和尺寸

位图contig_page_data.bdata->node_bootmem_map的起始地址跟在init_pg_tables_end的后面。大小等于所有物理页面数除以32,即每一位代表一个页面。

首先我们看文件arch/i386/kernel/setup.c中的setup_memory函数

min_low_pfn = PFN_UP(init_pg_tables_end);

然后看同样文件中的函数setup_bootmem_allocator

bootmap_size = init_bootmem(min_low_pfn, max_low_pfn);

在init_bootmem中min_low_pfn是init_pg_tables_end的页框号

最终在函数init_bootmem_core中我们看到

bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart));

其中mapstart就是min_low_pfn;bdata就是NODE_DATA(0),也就是contig_page_data.bdata

所以contig_page_data.bdata->node_bootmem_map就是init_pg_tables_end指向地址

我们前面已经介绍init_pg_tables_end的实际位置和内核大小有关

init_pg_tables_end= 内核保护模式代码启始地址(0x100000)+内核保护模式代码尺寸+pg0的1024个4字节页面描述符号+保证第一次分页设置的页表尺寸(一般还需要若干1024个4字节的页面描述符号,由内核尺寸决定)+描述1G 内存的位图尺寸128K字节+描述1G内存的页表空间(1024*4096字节)+间隔空间(4*4096字节)

可以看出如果内核尺寸在4M左右,描述1G内存也需要大量页表空间(4M),这样第一次分页设置实际上就至少需要3个页表的页描述符。

2.2内存位图的释放

在设置了区域和页面管理以后,内存位图就不需要了。释放内存位图的内存时,使用了函数free_pages_bootmem。

首先见启动过程中的mem_init()函数,这是在设置了区域和页面管理后执行的。我们看其中的 free_all_bootmem()调用,在free_all_bootmem_core中将bdata->node_bootmem_map的对应页面结构逐个调用free_pages_bootmem。

在free_pages_bootmem中首先清除了页面结构的PG_reserved标记,然后设置页面使用记数count为1,最后调用free_page(下面会详细描述)。

3。pte的内存分配

设置页表时,pte的内存分配使用了函数alloc_bootmem_low_pages,由于此时区域页面管理还未开始使用,使用的都是内存位图搜索。

在one_page_table_init中使用alloc_bootmem_low_pages为页表分配内存,大小为一个页面4096字节。

见mm/bootmem.c中的alloc_bootmem_low函数,最后还是使用了 alloc_bootmem_core,其中分配大小为PAGE_SIZE(实际上就是一个页面),对齐为PAGE_SIZE,启始搜寻地址为0,界限为 ARCH_LOW_ADDRESS_LIMIT。

首先如果设置了启始搜寻地址,则从启始搜寻地址开始向上找。使用 find_next_zero_bit查找bdata->node_bootmem_map从搜寻地址开始的第一个未分配页面(test_bit(i,bdata->node_bootmem_map),i为页面位),然后检查接下来的连续申请页面是否都为空余页面。在one_page_table_init中只需要申请一个页面。

找到申请页面并调整对齐以后,将页面转换为虚拟地址,即加上0xC0000000。并使用test_and_set_bit(i,bdata->node_bootmem_map)在内存位图中标记内存已经使用。最后返回虚拟地址。

4。页面信息结构page的内存分配

在区域管理中设置页面信息page时,由函数alloc_node_mem_map使用了调用alloc_bootmem_node实现,由于此时区域页面管理还未开始使用,使用的也是内存位图搜索 。

见mm/bootmem.c中的alloc_bootmem_node函数,最后也是使用了 alloc_bootmem_core,其中对齐使用SMP_CACHE_BYTES,启始搜寻地址为MAX_DMA_ADDRESS,界限为0。和 pte页表分配不同的是,这里的尺寸不再是一个页面。

start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1);这里的pgdat->node_start_pfn就是early_node_map[i].start_pfn,在 add_active_range(0, 0, max_low_pfn)里面定义,实际上就是0。

end = pgdat->node_start_pfn + pgdat->node_spanned_pages;pgdat->node_spanned_pages是系统中总共的页框数目

end = ALIGN(end, MAX_ORDER_NR_PAGES);

size = (end - start) * sizeof(struct page);需要的空间就是系统中页框数和页面结构的乘积,也就是为系统中存在的每一个页表建立一个页表结构

页表结构的内存搜索从MAX_DMA_ADDRESS以上寻找。0xC0000000+0x1000000=0xC1000000,即16M物理地址以上找空余内存。其它操作和分配pte页面内存一样。

分配后获得的页面结构内存指针放在pgdat->node_mem_map和mem_map中。

5。free_pages详解

free_pages

  • 如果只释放一页就调用free_hot_page,否则调用free_pages_ok,这里只介绍后者
    • free_one_page(page,      zone, order);要释放的页面指针page、页面所在区域指针zone和连续页面大小order
      • page_idx =       page_to_pfn(page) & ((1 << MAX_ORDER) - 1);取页框号的低11位
      • while       (order < MAX_ORDER-1) {
        • buddy =        page_find_buddy(page, page_idx, order);使用buddy算法合并页面,但合并的连续页面不能大于MAX_ORDER-1,下面会详细介绍伙伴算法       
        • if        (!page_is_buddy(page, buddy, order))
          • break;
        • list_del(&buddy->lru);将伙伴页面从空余空间列表中删除
        • area =        zone->free_area + order;找到当前order的空余页面信息指针
        • area->nr_free--;空余页面信息减1
        • rmv_page_order(buddy);设置伙伴页面属性
        • combined_idx        = find_combined_index(page_idx, order);合并后索引       
        • page =        page + (combined_idx - page_idx);指向合并后的页面指针       
        • page_idx =        combined_idx;page_idx是给page_find_buddy寻找伙伴的参数
        • order++;幂数加一
      • }
      • set_page_order(page,       order);设置页面伙伴信息
      • list_add(&page->lru,       &zone->free_area[order].free_list);将页面加入到空余空间列表
      • zone->free_area[order].nr_free++;对应空余空间记数加一
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值