copy_page_tables函数

2021/5/18 10:55:45

本文主要是介绍copy_page_tables函数,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

 1 int copy_page_tables(unsigned long from,unsigned long to,long size)
 2 {
 3     unsigned long * from_page_table;
 4     unsigned long * to_page_table;
 5     unsigned long this_page;
 6     unsigned long * from_dir, * to_dir;
 7     unsigned long nr;
 8 
 9     // 首先检测参数给出的原地址from和目的地址to的有效性。原地址和目的地址都需要
10     // 在4Mb内存边界地址上。否则出错死机,限制这样的要求是因为一个页表的1024项可
11     // 管理4Mb内存。源地址from和目的地址to只有满足这个要求才能保证从一个页表的
12     // 第一项开始复制页表项,并且新页表的最初所有项都是有效的。然后取得源地址和
13     // 目的地址的其实目录项指针(from_dir 和 to_dir).再根据参数给出的长度size计
14     // 算要复制的内存块占用的页表数(即目录项数)。
15     if ((from&0x3fffff) || (to&0x3fffff))
16         panic("copy_page_tables called with wrong alignment");

         // 计算给出的线性基地址对应的真实目录项。对应的目录项号=from>>22.因为每
         // 项占4字节,并且由于页目录表从物理地址0开始存放,因此实际目录项指针=目录
         // 项号<<2,也即(from>>20)。& 0xffc确保目录项指针范围有效,即用于屏蔽目录项
         // 指针最后2位。因为只移动了20位,因此最后2位是页表项索引的内容,应屏蔽掉。

17     from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
18     to_dir = (unsigned long *) ((to>>20) & 0xffc);
       

      //计算参数size给出的长度所占的页目录项数(4MB的进位整数倍),也即所占页表数
       //因为1个页表可管理4MB物理内存,所以这里用右移22位的方式把需要复制的内存长度值
       //除以4MB.其中加上0x3fffff(即4MB-1)用于得到进位整数倍结果,即操作若有余数则进1.
       //例如,如果原size=4.01Mb,那么可得到结果sieze=2
19     size = ((unsigned) (size+0x3fffff)) >> 22;
    // 在得到了源起始目录项指针from_dir和目的起始目录项指针to_dir以及需要复制的
21     // 页表个数size后,下面开始对每个页目录项依次申请1页内存来保存对应的页表,并
22     // 且开始页表项复制操作。如果目的目录指定的页表已经存在(P=1),则出错死机。
23     // 如果源目录项无效,即指定的页表不存在(P=1),则继续循环处理下一个页目录项。
24     for( ; size-->0 ; from_dir++,to_dir++) {
25         if (1 & *to_dir)
26             panic("copy_page_tables: already exist");
27         if (!(1 & *from_dir))
28             continue;
29         // 在验证了当前源目录项和目的目录项正常之后,我们取源目录项中页表地址
30         // from_page_table。为了保存目的目录项对应的页表,需要在主内存区中申请1
31         // 页空闲内存页。如果取空闲页面函数get_free_page()返回0,则说明没有申请
32         // 到空闲内存页面,可能是内存不够。于是返回-1值退出。
33         from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
        if (!(to_page_table = (unsigned long *) get_free_page()))
35             return -1;    /* Out of memory, see freeing */
36         // 否则我们设置目的目录项信息,把最后3位置位,即当前目录的目录项 | 7,
37         // 表示对应页表映射的内存页面是用户级的,并且可读写、存在(Usr,R/W,Present).
38         // (如果U/S位是0,则R/W就没有作用。如果U/S位是1,而R/W是0,那么运行在用
39         // 户层的代码就只能读页面。如果U/S和R/W都置位,则就有读写的权限)。然后
40         // 针对当前处理的页目录项对应的页表,设置需要复制的页面项数。如果是在内
41         // 核空间,则仅需复制头160页对应的页表项(nr=160),对应于开始640KB物理内存
42         // 否则需要复制一个页表中的所有1024个页表项(nr=1024),可映射4MB物理内存。
43         *to_dir = ((unsigned long) to_page_table) | 7;
44         nr = (from==0)?0xA0:1024;
45         // 此时对于当前页表,开始循环复制指定的nr个内存页面表项。先取出源页表的
46         // 内容,如果当前源页表没有使用,则不用复制该表项,继续处理下一项。否则
47         // 复位表项中R/W标志(位1置0),即让页表对应的内存页面只读。然后将页表项复制
48         // 到目录页表中。
49         for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
50             this_page = *from_page_table;
51             if (!(1 & this_page))
52                 continue;
53             this_page &= ~2;
54             *to_page_table = this_page;
55             // 如果该页表所指物理页面的地址在1MB以上,则需要设置内存页面映射数
56             // 组mem_map[],于是计算页面号,并以它为索引在页面映射数组相应项中
57             // 增加引用次数。而对于位于1MB以下的页面,说明是内核页面,因此不需
58             // 要对mem_map[]进行设置。因为mem_map[]仅用于管理主内存区中的页面使
59             // 用情况。因此对于内核移动到任务0中并且调用fork()创建任务1时(用于
60             // 运行init()),由于此时复制的页面还仍然都在内核代码区域,因此以下
61             // 判断中的语句不会执行,任务0的页面仍然可以随时读写。只有当调用fork()
62             // 的父进程代码处于主内存区(页面位置大于1MB)时才会执行。这种情况需要
63             // 在进程调用execve(),并装载执行了新程序代码时才会出现。
64             // *from_page_table = this_page; 这句是令源页表项所指内存页也为只读。
65             // 因为现在开始有两个进程公用内存区了。若其中1个进程需要进行写操作,
66             // 则可以通过页异常写保护处理为执行写操作的进程匹配1页新空闲页面,也
67             // 即进行写时复制(copy on write)操作。
68             if (this_page > LOW_MEM) {
69                 *from_page_table = this_page;
70                 this_page -= LOW_MEM;
71                 this_page >>= 12;
72                 mem_map[this_page]++;
73             }
74         }
75     }
76     invalidate();
77     return 0;
78 }

 



这篇关于copy_page_tables函数的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程