Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1214591
  • 博文数量: 122
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4004
  • 用 户 组: 普通用户
  • 注册时间: 2014-02-20 08:27
文章分类
文章存档

2016年(1)

2015年(21)

2014年(100)

分类: LINUX

2014-02-20 15:35:56


=============================================================
 内存管理
=============================================================

 

-------------------------------------------------------------
1 分页
-------------------------------------------------------------


1.1 CR3存放正在使用的页目录的物理地址

1.2 CR0的PG标志表示是否启用分页机制

1.3 pgd页全局目录

1.4 内核页表

1.4.1 内核维持一组自己使用的页表,在主内核页全局目录(init_mm.pgd)中,主内核页全局目录保存于swapper_pg_dir全局变量中

1.4.2 分两大段

1.4.2.1 映射低端内存<896M

1.4.2.2 映射高端内存896M+128M

1.5 线性地址转换(线性地址和物理地址)

1.5.1 内核态__pa,__va

1.5.2 用户态必须通过进程各级页表进行转换

页表项中存放的是物理地址,由MMU硬件直接使用。内核中如果需要使用相关页表项内容(比如进行地址转换),需要进行PA->VA的转换,比如:

点击(此处)折叠或打开

  1. #define pud_page(pud) \
  2. ((struct page *)__va (pud_val(pud) & PAGE_MASK))


-------------------------------------------------------------
2 分段
-------------------------------------------------------------



2.1 GDT全局描述符表(存放段描述符)

2.1.1 每个CPU一个

2.1.2 包含18个段描述符:内核、用户代码和数据段,TSS段,等

2.1.2.1 linux中内核、用户代码和数据段基址都是0,相当于没有启用分段

2.1.2.2 TSS,任务状态段,包含任务运行状态信息,如各寄存器(如SP)信息,在任务切换时使用

2.2 LDT

2.2.1 Linux中通常不使用,内核中定义了一个缺省的LDT供大多数进程共享default_ldt

2.3 内核代码段固定(32位为例):0xc0000000+0x100000


-------------------------------------------------------------
3 进程地址空间
-------------------------------------------------------------


3.1 每个进程有自己独立的页表(页目录)

3.2 0-3G的地址空间映射不同,但所有进程的3-4G的地址空间映射是相同的(因为内核地址空间是共享的),其页目录、页表相同,页目录中大于0xc0000000的线性地址对应的页目录项等于主内核页全局的相应表项

3.3 VMA


-------------------------------------------------------------
4 内存分配
-------------------------------------------------------------


4.1 内核态

4.1.1 按页分配

4.1.1.1 alloc_page,返回page指针

4.1.1.2 get_free_page返回线性地址

4.1.1.2.1 调用alloc_page

4.1.1.2.2 不能用于分配高端内存,因为内核态中高端内存,不能直接访问,没有直接对应的线性地址

4.1.1.2.1 只能从低端内存中分配,低端内存中的物理内存,通过偏移直接映射

4.1.1.3 vmalloc,非连续内存区分配

4.1.1.3.1 线性地址从896M+8M开始

4.1.1.3.2 每个vmalloc取由4k分割

4.1.1.3.3 最终调用alloc_page分配页,分配后需要修改内核页表对新分配的页进行地址映射,使vmalloc区对应的线性地址映射到高端内存(或其他zone内存)

4.1.1.3.4 通常从高端内存分配

4.1.1.4 高端内存分配,由内核地址空间中的896M开始的128M(默认,可配置)线性映射地址

4.1.1.4.1 vmalloc(最主要的方式)

4.1.1.4.2 永久和临时映射kmap

4.1.1.4.3 固定映射

4.1.2 小于页大小的空间分配

4.1.2.1 kmalloc

4.1.2.2 slab(kmem_cache_alloc)

4.2 用户态

4.2.1 malloc或mmap

4.2.1.1 最终进入内核,通过alloc_page(或get_free_page)分配

4.2.1.1.1 修改页表进行地址映射

4.3 内存分配实质只是在伙伴系统或slab中查找可用的page或结构

4.3.1 系统中所有的物理内存按页组织

4.3.2 所有可用内存由BIOS识别,并通过e820表提供给内核

4.3.3 所有物理内存对应的页(page结构)在系统初始化时就已经分配好了,存放于mem_map全局数组中

4.3.3.1 pfn页框号,按物理内存顺序组织,pfn作为索引的mem_map[pfn]可以得到相应的page结构指针

4.3.3.2 相反,通过page结构指针也可以得到相应的物理地址page-mem_map(页框号,pfn)<

4.3.4 内存分配后,通常只是得到相应的page结构,需要将其映射到线性地址空间中,才能使用

4.3.4.1 内核态映射

4.3.4.1.1 低端内存直接通过偏移映射,内核可直接访问

4.3.4.1.2 高端内存需要通过128M的地址空间映射(间接映射),三种方式

4.3.4.1.2.1 高端内存映射时修改内核页表

4.3.4.1.2.2 理论上,当进程修改3-4G的地址空间映射时,应该需要修改相应的页表,而且应该需要将相应修改同步到所有进程的页表中去,但是如果这样的话就太麻烦了。内核利用了主内核也全局目录,采用 了延迟的方式,在需要对3-4G地址空间进程重新映射时,只修改内核页表,然后在进程访问相应线性地址时,发生缺页异常,在缺页异常中判断内核页表中是否有相应的表项,如果有则将其拷贝到进程的页表中

4.3.4.1.2.2.1 通常是vmalloc和vfree时才需要重新映射内核地址空间和修改内核页表,因为内核中分配内存的其他方式(alloc_page,get_free_page,slab的分配接口等)都是从低端内存中分配内存,低端内存的线性地址都只是通过PAGE_OFFSET的偏移进行映射的,是固定的,是不需要重新映射的

4.3.4.2 用户态映射

4.3.4.2.1 通过页表映射

 

阅读(2528) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~