put_page
1 //// 把一物理内存页面映射到线性地址空间指定处。 2 // 或者说是把线性地址空间中指定地址address处的页面映射到主内存区页面page上。主 3 // 要工作是在相关页面目录项和页表项中设置指定页面的信息。若成功则返回物理页面地 4 // 址。在处理缺页异常的C函数do_no_page()中会调用此函数。对于缺页引起的异常,由于 5 // 任何缺页缘故而对页表作修改时,并不需要刷新CPU的页变换缓冲(或称Translation Lookaside 6 // Buffer - TLB),即使页表中标志P被从0修改成1.因为无效页表项不会被缓冲,因此当修改 7 // 了一个无效的页表项时不需要刷新。再次就表现为不用调用Invalidate()函数。 8 // 参数page是分配的主内存区中某一页面(页帧,页框)的指针;address是线性地址。 9 unsigned long put_page(unsigned long page,unsigned long address) 10 { 11 unsigned long tmp, *page_table; 12 13 /* NOTE !!! This uses the fact that _pg_dir=0 */ 14 15 // 首先判断参数给定物理内存页面page的有效性。如果该页面位置低于LOW_MEM(1MB) 16 // 或超出系统实际含有内存高端HIGH_MEMORY,则发出警告。LOW_MEM是主内存区可能 17 // 有的最小起始位置。当系统物理内存小于或等于6MB时,主内存区起始于LOW_MEM处。 18 // 再查看一下该page页面是否已经申请的页面,即判断其在内存页面映射字节图mem_map[] 19 // 中相应字节是否已经置位。若没有则需发出警告。 20 if (page < LOW_MEM || page >= HIGH_MEMORY) 21 printk("Trying to put page %p at %p\n",page,address); 22 if (mem_map[(page-LOW_MEM)>>12] != 1) 23 printk("mem_map disagrees with %p at %p\n",page,address); 24 // 然后根据参数指定的线性地址address计算其在也目录表中对应的目录项指针,并 25 // 从中取得二级页表地址。如果该目录项有效(P=1),即指定的页表在内存中,则从中 26 // 取得指定页表地址放到page_table 变量中。否则就申请一空闲页面给页表使用,并 27 // 在对应目录项中置相应标志(7 - User、U/S、R/W).然后将该页表地址放到page_table 28 // 变量中。 29 page_table = (unsigned long *) ((address>>20) & 0xffc); 30 if ((*page_table)&1) 31 page_table = (unsigned long *) (0xfffff000 & *page_table); 32 else { 33 if (!(tmp=get_free_page())) 34 return 0; 35 *page_table = tmp|7; 36 page_table = (unsigned long *) tmp; 37 } 38 // 最后在找到的页表page_table中设置相关页表内容,即把物理页面page的地址填入 39 // 表项同时置位3个标志(U/S、W/R、P)。该页表项在页表中索引值等于线性地址位21 40 // -- 位12组成的10bit的值。每个页表共可有1024项(0 -- 0x3ff)。 41 page_table[(address>>12) & 0x3ff] = page | 7; 42 /* no need for invalidate */ 43 return page; 44 }