第九讲+虚拟内存管理(一)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/* from <asm-i386/page.h> */
#define __pa(x)
((unsigned long)(x)-PAGE_OFFSET)
/* from <asm-i386/io.h> */ static inline unsigned long virt_to_phys(volatile void * address) {
管理区的类型可以是ZONE_DMA,ZONE_NORMAL 或ZONE_HIGHMEM
ZONE_DMA:用于DMA ZONE_NORMAL:可以直接映射到内核的区域 ZONE_HIGHMEM:高端内存,不能被直接映射到内核
2019/6/22
With the x86 the zones are:
每个进程有自己的用户空间,因此用户空间随着进程
的切换而切换(请思考:具体怎样切换?)
内核空间为所有进程共有,不随进程切换改变。实际 上这部分是内核代码运行的内存空间
x86系统结构下,用户空间占据0~3GB,内核空间占 据3~4GB
pgd = pgd_offset(mm, address); //取得全局页目录表项 if (pgd_none(*pgd) || pgd_bad(*pgd))
goto out;
pmd = pmd_offset(pgd, address); //取得中间页目录表项指针 if (pmd_none(*pmd) || pmd_bad(*pmd))
内核在初始化时根据物理内存的大小建立起一个 page结构体数组mem_map,作为物理页框的仓 库
每个page结构在这个数组内的下标就是该物理页框的 序号
mem_map数组通常放在ZONE_NORMAL的开始处
2019/6/22
page_data_t node_zones
ZONE_DMA
ZONE_NORMAL
ZONE_HIGHMEM
zone_mem_map
zone_mem_map
zone_mem_map
page
page
page
page
page
page
2019/6/22
Nodes,Zones 和 Pages关系图
节点(Nodes)
如前所述,一个节点用pg_data_t结构代表。在 <linux/mmzone.h>声明:
//该节点的第一个页面
unsigned long *valid_addr_bitmap; //描述节点内空洞的位图
struct bootmem_data *bdata;
unsigned long node_start_paddr; //节点起始物理地址
unsigned long node_start_mapnr;//在mem_map数组内的偏移
2019/6/22
假设一台的计算机中具有这样的结构:
CPU
内存
CPU
内存
内存
总线
CPU
内存
CPU
在这样的系统中,其物理存储空间虽然连续,“质地 ”却不一致,CPU访问各内存区域速度不一样,所以 称为“非均质存储结构(Non-Uniform Memory Architecture)”,简称NUMA
地址空间
内核角度看到的地址空间和进程角度看到的不一样 用户空间随着进程切换而改变,内核空间由所有进程
共有
2019/6/22
3.1 线性地址空间(Linear Address Space)
从进程的角度看,地址空间是平直的,线性的
从内核角度看,线性地址被分为两部分:用户空 间和内核空间
通过一个全局的mem_map数组来实现 mem_map是个page结构体数组,每个pages对应一个
物理页框 每个page结构在这个数组内的下标就是它对应的物理
页框的序号
2019/6/22
将page结构映射到物理地址
在x86结构上是简单的线性映射,只需将物理地址加 上3GB就得到其内核虚拟地址
char *name; unsigned long size; } zone_t;
//管理区名称 //管理区大小,以页面数计
2019/6/22
页面(Pages)
每一个物理页框都关联一个page结构体,用来追踪页框 的状态。page结构体声明于<linux/mm.h>:
typedef struct page { struct list_head list; struct address_space *mapping; unsigned long index; struct page *next_hash; atomic_t count; unsigned long flags; struct list_head lru; struct page **pprev_hash; struct buffer_head * buffers;
2 页表管理
要解决的主要问题:
Linux的地址映射模型? 怎样组织页表来描述映射模型? 怎样用线性地址来找到所属物理页面? 虚拟地址物理地址
2019/6/22
2.1 描述页目录
每个进程都拥有一个pgd_t结构体数组,占据一个物理页 框,叫作全局页目录(Page Global Directory,简称PGD ) 在x86上,通过将PGD的地址写入CR3寄存器来加载 一个进程的页表
//是否需要kswaped来平衡内存分配
free_area_t free_area[MAX_ORDER];
//空闲区位图
源自文库
wait_queue_head_t * wait_table; //等待释放页面的进程哈希表 unsigned long wait_table_size; //上述哈希表大小
unsigned long wait_table_shift;
线性地址的组成:
Global(PGD) Middle(PMD) Table(PTE)
Offset
2019/6/22
Page Table Layout
2019/6/22
x86的两层映射示意图
6
2
4
5 1
3
2019/6/22
例:一段follow_page()代码
pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte;
//映射到文件时使用
//映射到文件时的hash链 //引用计数 //状态标记 //LRU队列头
#if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL)
void *virtual;
//页面映射到内核空间时的地址
#endif
2019/6}/2m2 em_map_t;
typedef struct pglist_data {
zone_t node_zones[MAX_NR_ZONES];//节点包括的的管理区
zonelist_t node_zonelists[GFP_ZONEMASK+1];
int nr_zones; //管理区数量
struct page *node_mem_map;
typedef struct zone_struct {
spinlock_t lock; //保护该结构的自旋锁
unsigned long free_pages;
//空闲页面总数
unsigned long pages_min, pages_low, pages_high;
int need_balance;
ZONE_DMA
First 16MiB of memory
ZONE_NORMAL 16MiB – 896MiB
ZONE_HIGHMEM 896MiB – End
2019/6/22
页面(page)
系统的内存被划分为固定大小的块,称为页框( page frame)。每个物理页框由一个page(或 mem_map_t)结构体表示
2019/6/22
续
struct pglist_data *zone_pgdat; //指向所属节点
struct page *zone_mem_map;
//管理区第一个页面
unsigned long zone_start_paddr; //管理区起始物理地址
unsigned long zone_start_mapnr; //在mem_map数组内的偏移
Linux内核源代码导读
哈尔滨工业大学(威海)
嵌入式系统实验室
Spring 2012
Linux虚拟内存管理
1 描述物理内存 2 页表管理 3 进程地址空间
1 描述物理内存
均质存储结构与非均质存储结构
传统的计算机中,整个物理空间都是均匀一致的, CPU访问这个空间中任何一个地址所需时间都是相同 的,所以称为“均质存储结构(Uniform Memory Architecture)”,简称UMA
return __pa(address); }
2019/6/22
将page结构映射到物理地址
将物理地址右移PAGE_SHIFT位后当作mem_map数组 的下标即可找到对应的page结构
#define virt_to_page(kaddr) (mem_map + (__pa(kaddr)>>PAGE_SHIFT))
2019/6/22
节点(Node)
在NUMA 结构的系统中,属于同一个CPU节点的存 储器模块通常是匀质的,因此也被称为“存储节点 ” (Memory Node)
在Linux中,节点用一个名为pg_data_t的结构体来表 示。所有的节点通过pg_data_t->node_next指针被链入 一个叫做pgdat_list的单向链表
virt_to_page将虚拟地址kaddr作为输入参数,通过 __pa()宏将其转为物理地址,再将其右移 PAGE_SHIFT位转为数组下标,加上mem_map首地址 最终得到对应的page结构
2019/6/22
3 进程地址空间
现代OS采用虚拟存储器,每个进程都有自己的 虚拟地址空间,由OS负责映射到物理内存
每个pgd_t指向一个中间页目录(Page Middle Directory, 简称PMD),这是一个pmd_t结构体数组。每个PMD也 占一个物理页框
每个pmd_t又指向一个Page Table Entries(PTE),这是 一个pte_t结构体数组,大小同样为一个页框
每个pte_t最终指向包含用户数据的物理页框
unsigned long node_size;
//节点大小,即总页面数
int node_id;
//节点编号
struct pglist_data *node_next;
//指向下一个节点的指针
} pg_data_t;
2019/6/22
管理区(Zones)
一个管理区用zone_t结构代表。在 <linux/mmzone.h>声明:
goto out;
2019/6/22
ptep = pte_offset(pmd, address); if (!ptep)
goto out;
//取得页表项指针
pte = *ptep;
//得到页表项
2.2 将地址映射到page
Linux需要一种快速的方法来将虚拟地址到物理 地址,并将page结构映射到它的物理地址
2019/6/22
页目录和页表的表项格式:
页帧地址
AVL 0 0 D A 0 0 U W/ P
/S R
_PAGE_PRESENT—页面在内存没有被交换出去 _PAGE_PROTNONE-- Page is resident but not accessable _PAGE_RW-- Set if the page may be written to _PAGE_USER-- Set if the page is accessible from user space _PAGE_DIRTY-- Set if the page is written to _PAGE_ACCESSED-- Set if the page is accessed
UMA结构的计算机只有一个节点 分配一个页面时,Linux采取node-local allocation
policy从距离当前CPU最近的节点分配
2019/6/22
管理区(Zone)
每个节点内的物理内存又按照其地址被划分为几个管 理区(zone)。使用一个叫做zone_t的结构体来代表 每个管理区