Linux-0.11内核源码分析系列:内存管理copy_page_tables()函数分析

/*
 *Author  : DavidLin
 *Date    : 2014-11-22pm
 *Email   : [email protected] or [email protected]
 *world   : the city of SZ, in China
 *Ver     : 000.000.001
 *history :     editor      time            do
 *          1)LinPeng       2014-11-22      created this file!
 *          2)
 */
/*
 *  Well, here is one of the most complicated functions in mm. It
 * copies a range of linerar addresses by copying only the pages.
 * Let's hope this is bug-free, 'cause this one I don't want to debug :-)
 *
 * Note! We don't copy just any chunks of memory - addresses have to
 * be divisible by 4Mb (one page-directory entry), as this makes the
 * function easier. It's used only by fork anyway.
 *
 * NOTE 2!! When from==0 we are copying kernel space for the first
 * fork(). Then we DONT want to copy a full page-directory entry, as
 * that would lead to some serious memory waste - we just copy the
 * first 160 pages - 640kB. Even that is more than we need, but it
 * doesn't take any more memory - we don't copy-on-write in the low
 * 1 Mb-range, so the pages can be shared with the kernel. Thus the
 * special case for nr=xxxx.
 */

/* Linus认为下面copy_page_tables()函数是内存管理部分最难的之一
 * copy_page_tables()函数只被fork函数调用
 * 拷贝只是拷贝了一个页表,页表是管理4M地址的,所以按照4M对齐
 * 不拷贝物理页内容,当发生写时拷贝才会拷贝页表所管理的物理页内容
 * 对于进程0和1,只拷贝前160页共640Kb,出于效率考虑
 * 0-1M作为内核驻留地址区域,禁止写覆盖
 * 参数from,to是0-4G线性地址,size是字节为单位
 */
int copy_page_tables(unsigned long from,unsigned long to,long size)
{
	unsigned long * from_page_table;        //用于管理源页表
	unsigned long * to_page_table;          //用于管理目的页表
	unsigned long this_page;                //用于保存页表
	unsigned long * from_dir, * to_dir;     //用于管理源页目录项,目的页目录项
	unsigned long nr;                       //用于保存页表项个数

	if ((from&0x3fffff) || (to&0x3fffff))    //4M对齐检测,否则die
		panic("copy_page_tables called with wrong alignment");
	from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
                                                          //源页目录项
	to_dir = (unsigned long *) ((to>>20) & 0xffc);    //目的页目录项
	size = ((unsigned) (size+0x3fffff)) >> 22;        //页表项个数是字节数除以4M
	for( ; size-->0 ; from_dir++,to_dir++) {
		if (1 & *to_dir)    //如果目的页目录项已经被使用,die
			panic("copy_page_tables: already exist");
		if (!(1 & *from_dir))    //如果源页目录项未使用,跳过,不拷贝
			continue;
		from_page_table = (unsigned long *) (0xfffff000 & *from_dir);//取源页表
        if (!(to_page_table = (unsigned long *) get_free_page()))        //取空闲物理页为to_page_table赋值
            return -1;    /* Out of memory, see freeing */            //如果没有空闲物理页,die
        *to_dir = ((unsigned long) to_page_table) | 7;                   //将页表存进相应页目录项,7表示可读写
                                                                               //想一下常用的chmod 777 anyfile
        nr = (from==0)?0xA0:1024;                                        //如果是0地址,只拷贝160页,否则拷贝1024页
                                                                               //一个页目录表管理1024个页目录项
                                                                               //一个页表管理1024个页表项
                                                                               //一个页表项管理有4K物理地址
                                                                               
        for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
            this_page = *from_page_table;                             //从源页表中取源页表项
            if (!(1 & this_page))                                     //如果源页表项未被使用,跳过
                continue;
            this_page &= ~2;                                          //目的页表项读写位设置为只读                               
            *to_page_table = this_page;                               //将源页表项存进目的页表项
            if (this_page > LOW_MEM) {                                //如果是主内存区
                *from_page_table = this_page;                      //源页表项也要设置为只读
                this_page -= LOW_MEM;                              //取相对主内存的偏移地址
                this_page >>= 12;                                  //取主内存管理数组索引
                mem_map[this_page]++;                              //物理页引用次数加1
            }
        }
    }
    invalidate();                                                           //刷新高速缓存
    return 0;                                                               //返回0表示成功
}

				
时间: 2024-10-09 18:41:31

Linux-0.11内核源码分析系列:内存管理copy_page_tables()函数分析的相关文章

Linux0.11内核源码分析系列:内存管理copy_page_tables()函数分析

/*   *Author  : DavidLin   *Date    : 2014-11-22pm   *Email   : [email protected] or [email protected]   *world   : the city of SZ, in China   *Ver     : 000.000.001   *history :     editor      time            do   *          1)LinPeng       2014-11

Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装

原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底,同时在博文中如果那些地方有问题还请各位大神为我讲解. 今天我们会分析到以下内容: 1.      Linux体系结构简介 2.      Linux内核源码简介 3.      Linux内核配置.编译.安装 l  Linux体系结构简介 1.       Linux体系结构(linux系统构成)

Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析

Linux-0.11内存管理模块是源码中比較难以理解的部分,如今把笔者个人的理解发表 先发Linux-0.11内核内存管理get_free_page()函数分析 有时间再写其它函数或者文件的:) /*  *Author  : DavidLin  *Date    : 2014-11-11pm  *Email   : [email protected] or [email protected]  *world   : the city of SZ, in China  *Ver     : 000

Linux-0.11内核内存管理get_free_page()函数分析

/* *Author : DavidLin*Date : 2014-11-11pm*Email : [email protected] or [email protected]*world : the city of SZ, in China*Ver : 000.000.001*history : editor time do 1)LinPeng 2014-11-11 created this file! 2)*/Linux-0.11内存管理模块是源代码中比较难以理解的部分,现在把笔者个人的理解

redis源码解析之内存管理

zmalloc.h的内容如下: 1 void *zmalloc(size_t size); 2 void *zcalloc(size_t size); 3 void *zrealloc(void *ptr, size_t size); 4 void zfree(void *ptr); 5 char *zstrdup(const char *s); 6 size_t zmalloc_used_memory(void); 7 void zmalloc_enable_thread_safeness(v

Linux0.11内核源码——内核态进程切换的改进

由于Linux0.11的内核态进程切换使用的方式是用ljmp来进行TSS的跳转,效率较低,因此考虑对其进行优化,改为后面版本使用的kernel stack栈的切换 需要做的任务 1.重写schedule,switch_to函数 2.将修改过的函数接在一起 3.修改fork函数 目前 Linux 0.11 中工作的 schedule() 函数是首先找到下一个进程的数组位置 next,而这个 next 就是 GDT 中的 n,所以这个 next 是用来找到切换后目标 TSS 段的段描述符的,一旦获得

Linux 0.12和Linux 0.11内核学习——Google邮件列表

亲,你在学习Linux 0.12或0.11内核吗?快来加入我们吧,就缺你了!!! 为什么选用邮件列表呢?因为赵炯博士那个论坛交流不是很方便,经常发了贴没人回,人气相比十年前论坛刚成立时弱了不少.很多人,很多元老级别的人物,消失了...再也没有出现过. 而QQ群很繁杂,比如你肯定会因为一些兴趣爱好加入一些QQ群,但是也就刚加进去或者自己有什么要问的时候说几句,之后就屏蔽了,因为每天都有人在聊天,什么内容都有,想退群却又怕以后有用,不退吧又很烦,只能屏蔽了潜水. 而邮件列表,你可以订阅主题,实时追踪

Linux-0.11内核源码分析系列:关于线性地址,逻辑地址,物理地址的关系与区别

/* *Author : DavidLin *Date : 2014-11-22pm *Email : [email protected] or [email protected] *world : the city of SZ, in China *Ver : 000.000.001 *history : editor time do * 1)LinPeng 2014-11-22 created this file! * 2) */     以下所有描述基于Linux0.11内核及其所编写的年

Linux-0.11内核源码分析系列:内存管理up_wp_page()与do_wp_page()函数分析

/* * up_wp_page()函数用于解除物理页的共享状态,同时给发生写时复制的进程提供一页新的 * 物理页,新物理页是之前共享页的数据相同的拷贝. * table_entry是共享物理页的地址的指针,即页表实际地址+表内偏移地址 */ void un_wp_page(unsigned long * table_entry) { unsigned long old_page,new_page; old_page = 0xfffff000 & *table_entry; //取得共享物理页实际