内存管理1(内核情景分析)

linux定义了三层映射,页面目录称为PGD, 中间目录为PMD,页面表为PT.

linux将最高1G字节(0xc0000000-0xffffffff)用于内核本身称为"系统空间", 将较低3G字节(0x0-0xbfffffff)用作各个进程"用户空间".

以i386为例,从线性地址到物理地址的获取,在页面映射过程中,CPU需要访问内存三次,第一次页面目录,第二次页面表,第三次真正目标,所以虚存高效实现有赖于高速缓存实现。有高速缓存后一般都在高速缓存找到,不需要读内存,另一方面,整个过程是硬件实现,所以速度快。

linux为线性地址到物理地址的映射定义数据类型:pgd_t,pmd_t,pte_t。另一个说明页面保护的结构:pgprot_t,其中与i386MMU的页面表项的低12位相对应。
目录项结构:
typedef struct {
unsigned int ptba:20; /* 页表及地址的高 20 位*/
unsigned int avail:3; /* 供系统程序员使用 */
unsigned int g:1; /* global,全局性页面 */
unsigned int ps:1; /* 页面大小,0 表示 4K 字节 */
unsigned int reserved:1; /* 保留,永远是 0 */
unsigned int a:1; /* accessed已被访问过 */
unsigned int pcd:1; /* 关闭(不使用)缓冲存储器 */
unsigned int pwt:1; /* Write Through用于缓冲存储器 */
unsigned int u_s:1; /* 为 0时表示系统(或超级)权限,为 1时表示用户权限 */
unsigned int r_w:1; /* 只读或可写*/
unsigned int p:1; /* 为0时表示相应的页面不在内存中 */
} 目录项;
-----------------------------------------------------------------------------------
获得页表表项:
#define pgprot_val(x) ((x).pgprot)
#define __pte(x) ((pte_t) { (x) } )
#define __mk_pte(page_nr, pgprot) __pte(((page_nr)<<PAGE_SHIFT)|pgprot_val(pgprot))
------------------------------------------------------------------------------------

物理页面:内核中有个全局量mem_map,是个指向一个page数据结构数组,每个page数据结构代表一个物理页面,整个数组代表系统中的全部物理页面。对于软件,将页面表项的高20位作下标可以从mem_map找到代表这个物理页面的page数据结构。对于硬件,低12位补0就是物理页面的起始地址.
------------------------------------------------------------------------------------
根据虚存地址找相应物理页面:
#define pte_page(x) (mem_map+((unsigned long)(((x).pte_low >> PAGE_SHIFT))))
------------------------------------------------------------------------------------
物理页面mem_map_t的数据数组,根据数组下标划分成ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM管理区.每个管理区都有一个zone_struct(zone_t) 数据结构,每个结构都有一组"空闲空间"(free_area_t)队列.管理区数据结构中既要有一个队列来保持一些离散(连续长度为1)的物理页面,还要有一个队列来保持一个连续长度为2的页面块以及连续长度为4、8、16、…、直至2^MAX_ORDER的页面块。常数MAX_ORDER定义为10,也就是说最大的连续页面块可以达到2^10=1024个页面,即4M自己。(.....无语中,不懂,--->伙伴算法???)

引入NUMA后,在zone_struct解构上有了另一层代表着存储节点的pglist_data数据结构.

虚拟空间: vm_area_struct,mm_struct数据结构.



ps:物理空间像仓库,物理空间管理好比仓库管理;虚拟空间以进程为基础,从"需"的角度来管理.mm_struct和

vm_area_struct说明了对页面的需求,前面page,zone_struct等结构则说明了对页的供应;而页面目录,中间目录以及页面表则是两者中间桥梁.


linux在i386内存管理的特殊点:
1.i386从线性地址到物理地址是两级映射(MMU识别两层),PMD等同于PT.
2.内核GDT只使用了四种不同段寄存器,两种内核,两种用作所有进程.第2项和第3项分别用于内核的代码段和数据段,第4项和第5项永远用于当前进程的代码段和数据段.RPL等级内核0用户进程3.(见GDT寄存器定义)
typedef struct {
unsigned int index:13; /*  描述表项号*/
unsigned int ti:1; /* 选择GDTR或LDTR*/
unsigned int rpl:2; /* 特权等级 */
} 段描述表寄存器;
3.段描述符项使用平面地址,段描述符项2,3,4,5差不多,区别在于dpl(访问本段所需权限),s(描述项类型1表示系统0表示代码或数据),type(段的类型,读写,是否访问等).
ps:看2,3点得知linux内核装模作样的糊弄i386的段式处理.

问题1: 32位i386的linux中进程的最大理论数计算?
每个进程的局部段描述表LDT都作为一个独立的段而存在,在全局段描述表GDT中要有一个表项指向这个段的起始地址,并说明该段的长度以及其他一些参数。除上之外,每个进程还有一个TSS结构(任务状态段)也是一样。所以,每个进程都要在全局段描述表GDT中占据两个表项。那么,GDT的容量有多大呢?段寄存器中用作GDT表下标的位段宽度是13位,所以GDT中可以有8192个描述项。除一些系统的开销(例如GDT中的第2项和第3项分别用于内核的代码段和数据段,第4项和第5项永远用于当前进程的代码段和数据段,第1项永远是0,等等)以外,尚有8180个表项可供使用,所以理论上系统中最大的进程数量是4090。

问题2: i386、linux下,c语言中*和&,汇编中的符号地址到底是什么地址?
c语言用的是虚拟地址,汇编用的是线性地址。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章