第8章存储管理ppt课件.pptx
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《第8章存储管理ppt课件.pptx》由会员分享,可在线阅读,更多相关《第8章存储管理ppt课件.pptx(133页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、 如何进行存储管理,使系统在有限的硬件环境发挥出尽可能高的性能是存储管理的核心内容。一般Linux中的内存管理以及uClinux内存管理有什么特点。本章主要介绍了:缺少MMU支持的内存管理。内存管理3种模型。标准Linux的内存管理、uClinux内存管理及其的局限性。内存管理模块的启动过程。用户程序的内存分布、reloc段机制、可执行文件格式和执行文件加载流程。8.1 缺少缺少MMU支持的内存管理支持的内存管理 内存管理是操作系统中非常重要的子模块。如同普通操作系统一样,在嵌入式操作系统中,内存管理实现的好坏对系统性能有决定性的作用。Linux内核的内存管理子模块性能优越,目前大多数使用的嵌
2、入式Linux解决方案中都直接使用了标准Linux内存管理机制,或者对Linux内核的内存管理子模块做了很小的改动,但嵌入式Linux的内存管理仍然是值得关心的问题。目前的Linux内核已经被移植到大量的非x86平台上,包括ARM,M68K,PPC,Alpha,Sparc等。其中uClinux主要针对缺少MMU内存管理的优秀嵌入式Linux操作系统。目前,由于体积限制或者出于降低成本的考虑,嵌入式系统中所使用的微处理器大多缺少MMU。这些硬件平台包括数字信号处理器(DSP),SoC(System on Chip),以及那些不具有MMU的微处理器,例如ARM7TDMI,Motorola的M68K
3、龙珠系列等。这些没有MMU的微处理器为传统Linux的应用造成了一个障碍,它们要求使用flat内存模型即没有虚拟内存(分页页面交换)、内存地址转换(分段)和内存保护的内存管理机制。在基于Linux的嵌入式操作系统中,uClinux因为具有在不带内存管理单元(MMU)的硬件平台上运行的能力而独领风骚。它通过提供修改过的Linux内核、C库和编译器为嵌入式系统开发者提供了与标准Linux相同的APl,实现了从Linux到无MMU的微处理器上的无缝转化。目前,在无MMU平台上能够运行的Linux仅有uClinux一家。8.1.1 3种内存管理模型 操作系统的内存管理模型可以分成如下3种:1.单一程序
4、模型 这是没有硬件地址转换的内存管理模型。应用程序始终在物理内存中的同一地址空间运行,一个时刻只有一个应用程序被加载运行,程序加载器把应用程序加载到内存低端,将操作系统加载到高端。一个应用程序可以对所有的物理内存地址进行寻址。早期的操作系统受限于硬件能力多采用这种模型,现代操作系统中这种内存管理方式已经不见了。2.多程序模型 这也是没有硬件地址转换的内存管理模型。即使没有硬件地址转换功能,多个程序也可以共享相同的物理地址。在程序被加载到内存的时候,改变程序中寻址指令(load,store,jump)所使用的地址值为当前被加载到的位置。uClinux正是使用了这种模型。3.具有地址转换硬件的内存
5、管理模型 应用程序使用的是虚拟地址,CPU实际执行程序所使用的是物理地址,从虚拟地址到物理地址的转换需要操作系统和MMU(Memory Management Unit)硬件的参与。标准Linux以及大多数现代操作系统都使用这种内存管理模型。8.1.2 标准Linux的内存管理 为了理解uClinux对标准Linux的裁减,首先必须清楚标准Linux中内存管理的各种基本概念。这里对相关于虚拟内存的各个概念作一个总结。Linux使用了上述的第三个模型,即使用了地址转换硬件的内存管理模型。虚拟内存是一种对RAM和磁盘(或称做主存和辅存)进行无缝混合访问的技术。所有的虚拟内存对于应用程序来说好像是真的
6、存在一样,应用程序在加载的时候并不需要关心是否会超过系统中实际的物理RAM的大小 内核主要通过页目录和页表的地址转换功能将应用程序的虚拟地址转换成物理地址 这个过程中可能将应用程序中使用的超过了实际物理内存大小的虚拟地址映射到适当的真实物理地址,从而使应用程序可以随心所欲地使用巨大的虚拟存储空间(对Linux 2.4内核来说为4GB)。但是只通过地址映射还不能解决有限的物理内存被虚拟地址空间所使用的问题,操作系统还必须使用页面交换机制将那些暂时不再使用的内存空间交换到外存中以使其他程序,能够使用物理内存。Linux没有将整个进程所使用的空间都交换到外存中,而是对部分不再使用的大小为4KB 的页
7、面进行交换,这样就获得了更多的灵活性。应用程序在标准Linux中的加载使用了“按需调页”的策略,也就是说,应用程序在开始被加载的时候并没有一次被全部装载到内存中,只有那些现在必需的代码和数据在开始进行了加载。在程序执行的过程中,如果遇到了不在内存中的程序部分将产生页面错误,操作系统在处理这个错误中断的时候会到外存中找到相应的应用程序部分进行加载。这种设计是基于计算机科学中著名的90-10规则的:90的程序执行时间花费在整个程序10的代码上。所以只要保持我们用到的程序在内存中,就可以既满足程序的执行速度又节约物理内存空间。标准Linux中的内存管理模型如图8-1所示。8.1.3 uClinux的
8、内存管理 由于M68K系列微处理器中没有分段的概念,所以标准Linux内核中从虚拟地址到线性地址的映射已经不必存在了。而且由于缺少了MMU硬件的支持,uClinux不能支持虚拟内存管理和内存保护。这就意味着它完全不使用标准Linux内核中的分页管理机制,也就没有了页表和页目录对线性地址的映射,从而线性地址到物理地址的转换也是不需要进行任何工作的。换句话说,uClinux中所使用的都是直接物理地址。而且,由于没有了虚拟内存管理功能,uClinux不再使用“按需调页”算法。这样在程序载入内存执行的时候需要将程序的全部映像都一次装入。那些比物理内存还大的程序将无法执行。尽管如此,uClinux还是将
9、整个物理内存划分成大小为4KB的页面。由数据结构page管理,有多少页面就有多少page结构,它们又作为元素组成一个数组mem_map。物理页面可以作为进程的代码、数据和堆栈的一部分,还可以存储装入的文件,也可以当作缓冲区。uClinux仍然使用标准Linux内核中的变型Buddy System机制来管理空闲的物理页面,bitmap表和free_area数组,以及相关的函数或宏_get_free_pages()、free_pages()、_get_free_page()现在仍然在被使用。进程可以向核心申请使用物理内存。这仍然通过使用传统的kmalloc()和kfree()实现。这些内存块来自于
10、free_area数组,由blocksize表、size表、page_descriptor结构和block_header结构共同管理。而过去的vmalloc()和vfree()由于是从虚拟空间3GB以上的虚拟空间的最高端分配内存,所以现在对它们的实现只是简单地调用kmalloc()和kfree(),实际上分配的也是从空闲物理页面链表中获得的页面。不使用虚拟空间的概念,虚存段结构vm_area_struct以及由它构成的线性链表和AVL树都不再使用。没有了虚拟内存的应用,也就不再有将页面换出到外存中的机制。所以过去的kswapd页面换出守护进程和交换空间的页面管理数据结构在uClinux中都被删
11、除。8.1.4 uClinux内存管理的局限性 由于缺少了MMU硬件的支持,uClinux的多任务管理功能受到一定限制:1.uClinux中无法实现fork()而只能使用vfork()。这并不意味着uClinux不具有多任务功能,而是父进程在调用vfork()之后必须在子进程调用exec()或者exit()之前阻塞。2.标准Linux中的内存分段为应用程序提供了接近无限的堆空间和栈空间,而uClinux为可执行程序在紧随它的数据段结束处分配堆栈空间。这样如果堆增长的太大,它将可能覆盖程序的静态数据段和代码段。3.uClinux中没有自动扩展的栈,也没有brk()调用。用户必须通过使用mmap(
12、)来分配内存空间。可以在程序的编译过程中指定它所使用的栈大小。4.不具有内存保护。任何程序都有可能导致内核崩溃。uClinux与标准Linux的主要区别在于它针对没有MMU的处理器进行改造。uClinux所做的修改最大的部分理所当然位于内存管理部分,而内存管理上最大变化就是uClinux没有使用虚拟内存机制。这样,标准Linux的内存管理模块中的许多功能实际上都被抛弃了,诸如对页目录和页表的管理,对于交换空间的维护,页交换内核守护进程和页面换出功能,缺页中断和页面保护机制等。而为了解决由此产生的新问题,uClinux同时设计了一种新的可执行文件格式:flat,以及修改了部分进程管理的代码:如用
13、vfork()来代替了fork()调用,实现了无法共享页面的do_mmap()等。uClinux下的多任务管理远比Linux简单,因为没有进程的页表项和保护机制要处理。内核的调度器不需要进行修改,唯一需要完成的工作就是进行程序上下文的正确保存和恢复。这些上下文包括所有的在进程被中断的时候必须保存的寄存器的值。这些机制的缺少归根结底都在于微处理芯片没有MMU的支持。例如,在没有MMU的处理器上不可能实现内存共享和保护,这是由于各种UNIX的内存共享都是需要MMU中的页表和页目录管理功能支持的。标准Linux中的内存共享以页面共享的形式实现,共享该页的各个进程的页表项直接指向共享页,当共享状态发生
14、变化的时候共享该页的各进程的页表都进行修改。另一个例子是内存保护机制的缺少。标准Linux中对内存的加锁保护是在虚拟内存段VMA的基础上进行的,也就是每一个VMA段由一个自己的保护权限标志vm_flags,将这个标志设置成PROT_READ,PROT_ WRITE和PROT_EXEC就可以实现保护机制,但实际上在VMA操作的最底层,保护的实现还是要依靠各个页面本身的页表项标志。8.2 内存管理模块的启动初始化内存管理模块的启动初始化 在标准Linux的启动过程中要进行许多与内存管理相关的功能模块的初始化工作,诸如页目录和页表映射的建立等。在把它改造成不使用MMU的系统的过程中必然要对这些功能进
15、行修改。所以在这一部分中将展开对uClinux中内存模块的启动初始化分析。arch/armnommu/kernel/entry_armv.S是一个汇编文件,它包含了一个kernel_entry的定义,这是整个内核的进入点。在完成某些平台相关的初始化工作之后,执行流程跳转到start_kernel()处。从这里开始考察uClinux的内存模块启动初始化是如何实现的。start_kernel()中与内存模块相关的函数调用流程如下:setup_arch()paging_init()free_area_init()mem_init()下面分别分析这些函数各自的功能以及uClinux对它们的改造。8.2
16、.1 setup_arch()setup_arch()首先根据目前内核所配置的平台向某些特定地址写入特殊字符序列,以完成对特定硬件的初始化,比如工作状态发光二极管、错误和报警发光二极管等。存储了可用物理内存起始地址的变量memory_start的初始化是通过一个ld脚本中定义的变量_end进行的。ld脚本是用来控制GNU ld连接器在连接内核各个目标文件部分的时候的配置动作,比如这样一个脚本:SECTIONSSECTIONS .=0 x10000 .=0 x10000;.text.text:*(.text.text).=0 x8000000 .=0 x8000000;.data.data:*(
17、.data.data).bss:*(.bss).bss:*(.bss)用来配置ld连接目标文件的时候将所有目标文件中的存储程序正文的.text段(section)连接到一起,并且映射到输出文件的地址0 x10000处,将所有目标文件中已初始化的数据 data段连接到一起并放置到输出可执行文件的0 x8000000地址处,而所有目标文件中还未初始化的数据段.bss连接起来后映射到输出文件中紧跟在.data段之后的位置。这个ld配置脚本文件对每个平台都是不同的。如为MICETEK上所使用的uClinux版本使用的ld配置文件为arch/armnommu/vmLinux.lds。可以通过修改某个平台
18、上的ld脚本配置文件中的_end变量来达到配置其可用物理内存起始地址的目的。setup_arch()在完成对memory_start变量的初始化之后,通过某些特定手段检测不同类型的内存分布情况。比如为检测某段地址范围是否为RAM的方法是通过将某个地址的数据读出来,将它加1后写回内存地址中,然后再读出来和原始数据比较看看其值是否成功增加了1,这样反复操作两次,最后将原数据恢复。如果是可读可写的RAM,那么这个测试的结果就是每次比较都是成功的,否则就不能将这个地址当作RAM。在setup_arch()中还可能根据所用平台进行对flashmemory和ROM的测试。在这些平台相关的工作完成以后,se
19、tup_arch()将对系统运行的第一个进程init_task的mm_struct结构中描述地址空间分布的变量start_code,end_code,end_data和brk进行初始化,start_code为0,其他三个数值分别为来自于ld脚本配置文件中定义的相关变量_etext、_edata和_end。此后setup_arch()将根据Linux中为系统中的第块rom/flash memory card所分配的固定的主从设备号(可以从Documentdevicestxt中得到)来创建根文件系统的设备号,并存储在后来将要用到的全局变量ROOT_DEV中。Setup_arch()最后完成对系统启
20、动参数的保存。在调用setup_arch()返回之后,start_kernel()中得到了系统可用物理内存的起始和结束地址,以及系统启动时的命令行参数。8.2.2 paging_init()在Linux中,paging_init()的一项主要功能是建立页目录和页表,而且将Linux移植到不同平台的过程中非常重要的一个步骤就是修改这个函数来适应新的硬件平台的虚拟内存体系。但是由于在uClinux中不再使用虚拟内存机制,也就不再需要维护页目录和页表数据结构了,所以paging_init()在这里只是为系统启动的时候保留一部分特殊用途的内存区间。它返回后,从可以使用的内存区间开始,依次是如下的数据结
21、构:empty_bad_page_table 占用1页 empty_bad_page 占用1页 empty_zero_page 占用1页,并且被初始化为全0 mem_map bitmap paging_init()函数在返回前通过调用free_area_init(start_mem,end_mem)进行建立buddy system的映射位图关系,以及建立空闲物理页面链表的操作。8.2.3 free_area_init()这个函数用于建立管理物理页帧的数据结构mem_map,有多少物理页帧就有多少mem_map_t类型的结构体与之相对应。每个页面的mem_map_t结构中的flags被标明为PG
22、_DMA和PG_reserved,并且页帧号被赋给相应的数值。同时建立了管理空闲页面的bitmap映射表,并且所有的位都被清0。8.2.4 mem_init()mem_init()函数遍历整个可用物理内存地址空间,将每个页面相对应的struct page结构中flags的PG_reserved标志位清除,标志用户个数的count计数器置1,并同时统计可用物理页面数量,然后打印系统的各个内存参数,如可用RAM和ROM的大小、内核代码段和数据段大小等。8.3 可执行程序的加载 在普通的Linux中,虚拟内存技术的使用使我们不必关心一个应用程序是从什么地址开始的。即使所有的应用程序都使用同一个连接脚
23、本配置。也就是说,即使它们使用的虚拟地址是重叠的,经过页表和页目录的转换之后它们也可以被映射到不同的物理地址。但是在uClinux中,由于缺少了MMU的硬件支持,在内核中不会发生地址的映射转换,这样就必须解决应用程序的加载问题。uClinux系统使用flat可执行文件格式,gcc的编译器不能直接形成这种文件格式,但是可以首先编译生成coff可执行格式或者elf可执行格式的文件,然后使用格式转化工具(coff2flt或者elf2flt)将这些中间代码转换成flat文件格式。当用户执行一个flat格式的可执行程序时,内核的执行文件加载器将对flat文件进行进一步处理,主要是对reloc段进行修正。
24、下面对do_load_flat_binary()函数的分析将详细描述其实现过程。8.3.1 用户程序的内存分布 1.堆 标准Linux上用户程序的动态内存分配是通过调用glibc库的malloc函数从程序的堆空间中获得内存页面。在虚拟内存系统中malloc是使用sbrk调用将程序的数据段向后扩展得到。应用程序的内存使用分布图如图8-2所示。而在uClinux的平地址模式中,堆空间是通过mmap调用获得的。uClibc中的malloc函数是一个非常简单的实现,它将所有分配内存的细节都交给了内核。2.栈 uClinux中的栈紧随着用户程序的数据段,而堆是从栈底向下扩张的,如图8-2所示。由于uCl
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 存储 管理 ppt 课件
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内