📄 memory.c
字号:
/* no need for invalidate */ return page;}void un_wp_page(unsigned long * table_entry)/*参数为页表项,若其所对应页非共享(引用计数为1)则将该页设为可写并返回 */{ /*若其所对应页为共享(引用计数大于1),则申请新页,并将原页内容复制进来 */ unsigned long old_page,new_page; old_page = 0xfffff000 & *table_entry; if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) { /*若该页被引用次数为1,则说明该页未被共享,直接将该页设为可写并返回 */ *table_entry |= 2; invalidate(); return; } if (!(new_page=get_free_page()))/*若该页被引用次数大于1,则说明是共享页面,需申请新页 */ oom();/*内存不够处理 */ if (old_page >= LOW_MEM) mem_map[MAP_NR(old_page)]--; *table_entry = new_page | 7; invalidate(); copy_page(old_page,new_page);/*复制页 */} /* * This routine handles present pages, when users try to write * to a shared page. It is done by copying the page to a new address * and decrementing the shared-page counter for the old page. * * If it's in code space we exit with a segment error. */void do_wp_page(unsigned long error_code,unsigned long address)/*写保护函数 */{#if 0/* we cannot do this yet: the estdio library writes to code space *//* stupid, stupid. I really want the libc.a from GNU */ if (CODE_SPACE(address))/*若欲写进程的代码段,则直接中止进程*/ do_exit(SIGSEGV);#endif un_wp_page((unsigned long *) (((address>>10) & 0xffc) + (0xfffff000 & /*给定线性地址转换为对应页表项物理地址 */ *((unsigned long *) ((address>>20) &0xffc)))));}void write_verify(unsigned long address)/*写页面验证,若该页不存在则直接退出(do_no_page会处理),参数为线性地址 */{ /*若该页存在且不可写则执行un_wp_page,否则直接退出*/ unsigned long page; if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1)) return; page &= 0xfffff000; page += ((address>>10) & 0xffc); if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */ un_wp_page((unsigned long *) page); return;}void get_empty_page(unsigned long address)/*get_free_page加pute_page,参数为线性地址 */{ unsigned long tmp; if (!(tmp=get_free_page()) || !put_page(tmp,address)) { free_page(tmp); /* 0 is ok - ignored */ oom(); }}/* * try_to_share() checks the page at address "address" in the task "p", * to see if it exists, and if it is clean. If so, share it with the current * task. * * NOTE! This assumes we have checked that p != current, and that they * share the same executable. */static int try_to_share(unsigned long address, struct task_struct * p)/*address为逻辑地址(0-64mb)*/{ /*若当前进程address处的页不存在则使当前进程共享进程p中adress处的页,若存在则出错*/ unsigned long from; unsigned long to; unsigned long from_page; unsigned long to_page; unsigned long phys_addr; from_page = to_page = ((address>>20) & 0xffc); from_page += ((p->start_code>>20) & 0xffc);/*获得p进程中逻辑地址address所在地址对应的目录项*/ to_page += ((current->start_code>>20) & 0xffc);/*获得当前进程中逻辑地址address所在地址对应的目录项*//* is there a page-directory at from? */ from = *(unsigned long *) from_page; if (!(from & 1)) return 0; from &= 0xfffff000; from_page = from + ((address>>10) & 0xffc); phys_addr = *(unsigned long *) from_page;/*获得p进程中逻辑地址address所在地址对应的页表项的内容*//* is the page clean and present? */ if ((phys_addr & 0x41) != 0x01)/*p进程中逻辑地址address所在地址对应的物理页面是否存在且干净*/ return 0; phys_addr &= 0xfffff000;/*获得p进程中逻辑地址address所在地址对应的物理页地址*/ if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM) return 0; to = *(unsigned long *) to_page; if (!(to & 1))/*若当前进程页目录项不存在则申请一新项*/ if (to = get_free_page()) *(unsigned long *) to_page = to | 7; else oom(); to &= 0xfffff000; to_page = to + ((address>>10) & 0xffc); if (1 & *(unsigned long *) to_page) /*若当前进程address处的页已存在则出错*/ panic("try_to_share: to_page already exists");/* share them: write-protect */ *(unsigned long *) from_page &= ~2; *(unsigned long *) to_page = *(unsigned long *) from_page; /*当前进程复制p进程的页表项*/ invalidate(); phys_addr -= LOW_MEM; phys_addr >>= 12; mem_map[phys_addr]++; return 1;}/* * share_page() tries to find a process that could share a page with * the current one. Address is the address of the wanted page relative * to the current data space. * * We first check if it is at all feasible by checking executable->i_count. * It should be >1 if there are other tasks sharing this inode. */static int share_page(unsigned long address) /*尝试共享文件,adress为进程逻辑地址*/{ /* 通过executable—>i_count(指针所指节点(进程运行的执行文件)的引用计数)来判断当前运行的程序是否有多个拷贝,若是则尝试他们之间的页面共享操作*/ struct task_struct ** p; if (!current->executable) return 0; if (current->executable->i_count < 2) /* 通过executable—>i_count(指针所指节点(进程运行的执行文件)的引用计数)来判断当前运行的程序是否有多个拷贝,若是则尝试他们之间的页面共享操作*/ return 0; for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { if (!*p) continue; if (current == *p) continue; if ((*p)->executable != current->executable) continue; if (try_to_share(address,*p)) return 1; } return 0;}void do_no_page(unsigned long error_code,unsigned long address) /*缺页处理,先尝试页面共享,若失败再从设备上读入相应页*/{ int nr[4]; unsigned long tmp; unsigned long page; int block,i; address &= 0xfffff000; tmp = address - current->start_code; /*计算线性地址adress对应的进程逻辑地址(页起始地址)*/ if (!current->executable || tmp >= current->end_data) { /*若exectuable为空(说明为进程0进程1)或地址超出进程代码数据段则说明申请的是堆栈*/ get_empty_page(address); return; } if (share_page(tmp)) /*否则说明地址在执行文件范围内,尝试共享页面*/ return; if (!(page = get_free_page())) /*若尝试共享文件失败,则申请一新页并从设备上读入文件数据*/ oom();/* remember that 1 block is used for header */ block = 1 + tmp/BLOCK_SIZE; for (i=0 ; i<4 ; block++,i++) nr[i] = bmap(current->executable,block); bread_page(page,current->executable->i_dev,nr); /*从设备上读入数据并存入新页中*/ i = tmp + 4096 - current->end_data; /*若读如的是文件结尾数据(可能不足一页),则需将超出部分截去*/ tmp = page + 4096; while (i-- > 0) { tmp--; *(char *)tmp = 0; } if (put_page(page,address)) /*将新页映射到进程线性地址中*/ return; free_page(page); oom();}void mem_init(long start_mem, long end_mem)/*主内存初始化*/{ int i; HIGH_MEMORY = end_mem; for (i=0 ; i<PAGING_PAGES ; i++) /*1-16mb的内存全标记为已使用(即mem_map数组中的对应项置位)*/ mem_map[i] = USED; i = MAP_NR(start_mem); /*计算主内存起始位置的页号*/ end_mem -= start_mem; end_mem >>= 12; while (end_mem-->0) /*主内存中所有页面在mem_map数组中的对应项清0*/ mem_map[i++]=0;}void calc_mem(void) /*计算内存空闲页面数并显示*/{ int i,j,k,free=0; long * pg_tbl; for(i=0 ; i<PAGING_PAGES ; i++) if (!mem_map[i]) free++; printk("%d pages free (of %d)\n\r",free,PAGING_PAGES); for(i=2 ; i<1024 ; i++) { if (1&pg_dir[i]) { pg_tbl=(long *) (0xfffff000 & pg_dir[i]); for(j=k=0 ; j<1024 ; j++) if (pg_tbl[j]&1) k++; printk("Pg-dir[%d] uses %d pages\n",i,k); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -