ImageVerifierCode 换一换
格式:DOCX , 页数:26 ,大小:23.79KB ,
资源ID:9944854      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/9944854.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(linux内存管理分析2.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

linux内存管理分析2.docx

1、linux内存管理分析2linux内存管理分析【二】 2012-11-19 21:09:22| 分类: 默认分类 | 标签: |字号大中小 订阅 2 内存管理系统建立过程为建立内存管理系统,在内核初始化过程中调用了下面几个函数:init/main.casmlinkage void _init start_kernel(void).初始化持久映射与临时映射的一些信息,后面持久映射和临时映射一节将详细讲解page_address_init();setup_arch是特定于体系架构的函数,负责初始化自举分配器和内核页表等。setup_arch(&command_line);.初始化per_cpu机制

2、的一些结构,将.data.percpu段中的数据拷贝到每个CPU的数据段中setup_per_cpu_areas();.建立结点和内存域之间的关系build_all_zonelists(NULL);. 停用自举分配器bootmem,迁移到实际的内存管理中,初始化slab分配器,初始化进程虚拟地址空间管理结构mm_init();.为每一个内存区域分配per_cpu_pageset结构并初始化其成员setup_per_cpu_pageset();.【start_kernel-setup_arch】arch/arm/kernel/setup.cvoid _init setup_arch(char *

3、cmdline_p)struct machine_desc *mdesc;内核参数可以通过平坦设备树或者tags由bootloader传递给内核。每一个机器平台都由一个struct machine_desc结构来描述,内核所支持的所有平台对应的machine_desc结构都包含在段.init.arch.info的 _arch_info_begin 到 _tagtable_end之间。但每一个平台都有其唯一的机器码machine_arch_type,可通过机器码在段.init.arch.info中找到对应的平台描述结构。 函数setup_machine_tags就是根据机器码找到对应的平台描述结

4、构,并且分析内核参数中内存相关的信息,用以初始化内存块管理结构membank。mdesc = setup_machine_fdt(_atags_pointer);if (!mdesc)mdesc = setup_machine_tags(machine_arch_type);machine_desc = mdesc;machine_name = mdesc-name;根据mdesc-dma_zone_size设置DMA区域的大小arm_dma_zone_size,和DMA区域的结束地址arm_dma_limitsetup_dma_zone(mdesc);结构struct mm_struct 管

5、理进程的虚拟地址空间,所有内核线程都使用共同的地址空间,因为他们都是用相同的地址映射,这个地址空间由init_mm来描述。_text 和_etext表示内核镜像代码段的起始和结束位置,_etext和_edata之间是已初始化数据段,_edata到_end是未初始化数据段等,_end之后便是堆区。init_mm.start_code = (unsigned long) _text;init_mm.end_code = (unsigned long) _etext;init_mm.end_data = (unsigned long) _edata;init_mm.brk = (unsigned l

6、ong) _end;内核命令行参数在函数setup_machine_tags获取并保存在了boot_command_line中strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);*cmdline_p = cmd_line;分析命令行参数,主要关注一些与内存相关的东西parse_early_param();将内存块按从小到大排序sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank0), meminfo_cmp, NULL);扫描各个内存块,检测低端内存的最大值arm_lowm

7、em_limit,设置高端内存起始值的虚拟地址high_memorysanity_check_meminfo();将所有内存块添加到结构memblock的memory区中,将已使用的内存添加到reserved区中去。arm_memblock_init(&meminfo, mdesc);创建内核页表,初始化自举分配器paging_init(mdesc);内核中将许多物理资源用struct resource结构来管理,下面函数就是将IO内存作为resource注册到内核request_standard_resources(mdesc);.如果内核命令行中有预留用于内核crash是的转存空间,就将这

8、些存储空间标记为已分配 reserve_crashkernel();.【start_kernel-setup_arch-setup_machine_tags】arch/arm/kernel/setup.cstatic struct machine_desc * _init setup_machine_tags(unsigned int nr)struct tag *tags = (struct tag *)&init_tags;struct machine_desc *mdesc = NULL, *p;char *from = default_command_line;init_tags.me

9、m.start = PHYS_OFFSET;下面循环根据机器号在段.init.arch.info中寻找对应的machine_desc结构for_each_machine_desc(p)if (nr = p-nr) printk(Machine: %sn, p-name);mdesc = p;break;.Bootloader传入的参数地址存放在_atags_pointer中if (_atags_pointer)tags = phys_to_virt(_atags_pointer);else if (mdesc-atag_offset)tags = (void *)(PAGE_OFFSET +

10、mdesc-atag_offset);.内核参数是由struct tag来管理,其中第一个tag类型必然是ATAG_COREif (tags-hdr.tag != ATAG_CORE) .tags = (struct tag *)&init_tags;内核提供的一个默认参数列表函数mdesc-fixup中一般会获取内存块的信息if (mdesc-fixup)mdesc-fixup(tags, &from, &meminfo);if (tags-hdr.tag = ATAG_CORE) 如果内存块已经初始化,就将参数列表中关于内存的参数标记为ATAG_NONEif (meminfo.nr_ban

11、ks != 0)squash_mem_tags(tags);将参数列表拷贝到一个静态数组atags_copy中save_atags(tags);分析内核参数,后面细讲parse_tags(tags);将解析出来的内核命令行信息拷贝到静态数组boot_command_line中。在内核启动期间用了很多静态存储空间,它们前面缀有_initdata,像这样的空间在内核启动起来后将被释放strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);return mdesc;【start_kernel-setup_arch-setup_machine_tags-

12、parse_tags】arch/arm/kernel/setup.cstatic void _init parse_tags(const struct tag *t)遍历参数列表中每一个参数结构for (; t-hdr.size; t = tag_next(t)if (!parse_tag(t).【start_kernel-setup_arch-setup_machine_tags-parse_tags-parse_tag】arch/arm/kernel/setup.cstatic int _init parse_tag(const struct tag *tag)extern struct

13、tagtable _tagtable_begin, _tagtable_end;struct tagtable *t;参数类型多种多样解析方式也各不相同,所有针对每一种参数类型都有一个对应的解析函数,这些解析函数和其参数类型由结构struct tagtable来管理。这些结构都存放在段.init.tagtable的_tagtable_begin和_tagtable_end之间。for (t = &_tagtable_begin; t hdr.tag = t-tag) t-parse(tag);break;return t u.mem.start, tag-u.mem.size);_tagtab

14、le(ATAG_MEM, parse_tag_mem32);【parse_tag_mem32-arm_add_memory】从ATAG_MEM参数中获取内存信息,初始化内存块管理结构int _init arm_add_memory(phys_addr_t start, unsigned long size)struct membank *bank = &meminfo.bankmeminfo.nr_banks;if (meminfo.nr_banks = NR_BANKS) printk(KERN_CRIT NR_BANKS too low, ignoring memory at 0x%08l

15、lxn, (long long)start);return -EINVAL;size -= start & PAGE_MASK;bank-start = PAGE_ALIGN(start);#ifndef CONFIG_LPAEif (bank-start + size start) size = ULONG_MAX - bank-start;#endifbank-size = size & PAGE_MASK;if (bank-size = 0)return -EINVAL;meminfo.nr_banks+;return 0;【start_kernel-setup_arch-sanity_

16、check_meminfo】arch/arm/mm/mmu.cvoid _init sanity_check_meminfo(void)int i, j, highmem = 0;遍历每一个内存块for (i = 0, j = 0; i start ULONG_MAX)highmem = 1;#ifdef CONFIG_HIGHMEMvmalloc_min在文件arch/arm/mm/mmu.c中定义,它定义了高端内存的起始位置。PAGE_OFFSET是物理位置的起始处。如果内存块起始位置大于vmalloc_min,表示存在高端内存。如果内存扩展超过32位,它就有可能小于PAGE_OFFSET

17、。if (_va(bank-start) = vmalloc_min |_va(bank-start) highmem = highmem;如果该内存块部分处于高端内存中,部分处于低端内存中就将其分为两个内存块。if (!highmem & _va(bank-start) size vmalloc_min - _va(bank-start) if (meminfo.nr_banks = NR_BANKS) . else memmove(bank + 1, bank,(meminfo.nr_banks - i) * sizeof(*bank);meminfo.nr_banks+;i+;bank1

18、.size -= vmalloc_min - _va(bank-start);bank1.start = _pa(vmalloc_min - 1) + 1;bank1.highmem = highmem = 1;j+;bank-size = vmalloc_min - _va(bank-start);#else 如果不支持高端内存做如下处理bank-highmem = highmem;if (highmem) .continue;if (_va(bank-start) = vmalloc_min |_va(bank-start) start + bank-size) vmalloc_min |

19、_va(bank-start + bank-size) start) unsigned long newsize = vmalloc_min - _va(bank-start);.bank-size = newsize;#endif求出低端内存的最大地址值if (!bank-highmem & bank-start + bank-size arm_lowmem_limit)arm_lowmem_limit = bank-start + bank-size;j+;.meminfo.nr_banks = j; 记录内存块数计算高端内存起始地址,该值不一定等于 vmalloc_min,因为可能没有高

20、端内存high_memory = _va(arm_lowmem_limit - 1) + 1;memblock_set_current_limit(arm_lowmem_limit);【start_kernel-setup_arch-arm_memblock_init】arch/arm/mm/init.cvoid _init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)int i;将所有内存模块添加到memblock.memory中。结构体memblock在文件mm/memblock.c中定义,如下:stru

21、ct memblock memblock _initdata_memblock = .memory.regions = memblock_memory_init_regions,.reserved.regions = memblock_reserved_init_regions,.;for (i = 0; i nr_banks; i+)memblock_add(mi-banki.start, mi-banki.size);如果内核在rom中运行就只将它的数据段开始的空间添加到memblock.reserved中,否则将内核代码段开始的空间添加到memblock.reserved中。#ifdef

22、 CONFIG_XIP_KERNELmemblock_reserve(_pa(_sdata), _end - _sdata);#elsememblock_reserve(_pa(_stext), _end - _stext);#endif#ifdef CONFIG_BLK_DEV_INITRD如果支持initrd启动,此时它还不在内存中if (phys_initrd_size &!memblock_is_region_memory(phys_initrd_start, phys_initrd_size) pr_err(INITRD: 0x%08lx+0x%08lx is not a memor

23、y region - disabling initrdn,phys_initrd_start, phys_initrd_size);phys_initrd_start = phys_initrd_size = 0;if (phys_initrd_size &memblock_is_region_reserved(phys_initrd_start, phys_initrd_size) pr_err(INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrdn,phys_initrd_start, phys_i

24、nitrd_size);phys_initrd_start = phys_initrd_size = 0;为inird镜像预留一块存储区if (phys_initrd_size) memblock_reserve(phys_initrd_start, phys_initrd_size);initrd_start = _phys_to_virt(phys_initrd_start);initrd_end = initrd_start + phys_initrd_size;#endif为内核页表分配存储空间arm_mm_memblock_reserve();.【start_kernel-setup

25、_arch-paging_init】arch/arm/mm/mmu.cvoid _init paging_init(struct machine_desc *mdesc)void *zero_page;memblock_set_current_limit(arm_lowmem_limit);根据不同的arm版本初始化不同的mem_types,该结构存放着页表的一些属性相关信息build_mem_type_table();将除了内核镜像、主内存所在虚拟地址之外全部内存的页表清除掉prepare_page_table();为低端内存的所有区域创建内核页表map_lowmem();对DMA区域重新创

26、建页表dma_contiguous_remap();为设备IO空间和中断向量表创建页表,并刷新TLB和缓存devicemaps_init(mdesc);获取持久映射区页表的位置,存储在pkmap_page_table中kmap_init();高64K是用于存放中断向量表的top_pmd = pmd_off_k(0xffff0000);分配一个0页,该页用于写时复制机制。zero_page = early_alloc(PAGE_SIZE);初始化自举内存分配,后面有专门章节讲解bootmem_init();empty_zero_page = virt_to_page(zero_page);刷新数

27、据缓存_flush_dcache_page(NULL, empty_zero_page);【start_kernel-setup_arch-paging_init-prepare_page_table】arch/arm/mm/mmu.cstatic inline void prepare_page_table(void)unsigned long addr;phys_addr_t end;模块加载的范围应该是在MODULES_VADDR到MODULES_END之间,MODULES_VADDR在文件arch/arm/include/asm/memory.h中定义,如下:#define MODUL

28、ES_VADDR (PAGE_OFFSET - 8*1024*1024)对于arm处理器,该区域在正常内核虚拟地址之下。清除存储空间在MODULES_VADDR之下的页表项。for (addr = 0; addr MODULES_VADDR; addr += PMD_SIZE)pmd_clear(pmd_off_k(addr);#ifdef CONFIG_XIP_KERNELaddr = (unsigned long)_etext + PMD_SIZE - 1) & PMD_MASK;#endiffor ( ; addr = arm_lowmem_limit)end = arm_lowmem_

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1