复制页目录项和页表的函数是
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 new_page; 8 unsigned long nr; 9 10 if ((from&0x3fffff) || (to&0x3fffff)) 11 panic("copy_page_tables called with wrong alignment"); 12 from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */ 13 to_dir = (unsigned long *) ((to>>20) & 0xffc); 14 size = ((unsigned) (size+0x3fffff)) >> 22; 15 for( ; size-->0 ; from_dir++,to_dir++) { 16 if (1 & *to_dir) 17 panic("copy_page_tables: already exist"); 18 if (!(1 & *from_dir)) 19 continue; 20 from_page_table = (unsigned long *) (0xfffff000 & *from_dir); 21 if (!(to_page_table = (unsigned long *) get_free_page())) 22 return -1; /* Out of memory, see freeing */ 23 *to_dir = ((unsigned long) to_page_table) | 7; 24 nr = (from==0)?0xA0:1024; 25 for ( ; nr-- > 0 ; from_page_table++,to_page_table++) { 26 this_page = *from_page_table; 27 if (!this_page) 28 continue; 29 if (!(1 & this_page)) { 30 if (!(new_page = get_free_page())) 31 return -1; 32 read_swap_page(this_page>>1, (char *) new_page); 33 *to_page_table = this_page; 34 *from_page_table = new_page | (PAGE_DIRTY | 7); 35 continue; 36 } 37 this_page &= ~2; 38 *to_page_table = this_page; 39 if (this_page > LOW_MEM) { 40 *from_page_table = this_page; 41 this_page -= LOW_MEM; 42 this_page >>= 12; 43 mem_map[this_page]++; 44 } 45 } 46 } 47 invalidate(); 48 return 0; 49 }
调用这个函数是在
1 int copy_mem(int nr,struct task_struct * p) 2 { 3 unsigned long old_data_base,new_data_base,data_limit; 4 unsigned long old_code_base,new_code_base,code_limit; 5 6 code_limit=get_limit(0x0f); 7 data_limit=get_limit(0x17); 8 old_code_base = get_base(current->ldt[1]); 9 old_data_base = get_base(current->ldt[2]); 10 if (old_data_base != old_code_base) 11 panic("We don't support separate I&D"); 12 if (data_limit < code_limit) 13 panic("Bad data_limit"); 14 new_data_base = new_code_base = nr * TASK_SIZE; 15 p->start_code = new_code_base; 16 set_base(p->ldt[1],new_code_base); 17 set_base(p->ldt[2],new_data_base); 18 if (copy_page_tables(old_data_base,new_data_base,data_limit)) { 19 free_page_tables(new_data_base,data_limit); 20 return -ENOMEM; 21 } 22 return 0; 23 }
其中old_data_base是父进程ldt的基地址,new_data_base是子进程ldt的基地址,data_limit是ldt段的长度
copy_page_tables的作用是复制由old_data_base和data_limit所决定内存空间所占用的页目录项和页表(个数由data_limit决定),其实现是由线性地址找到页目录项,再找到页表,复制父进程页表的每一项到子进程的页表中(申请的)
为什么说是页目录项,因为页目录只有一个,各个进程共用统一个页目录,但是每个进程的页目录项是不同的,详见fork.c
1 int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, 2 long ebx,long ecx,long edx, long orig_eax, 3 long fs,long es,long ds, 4 long eip,long cs,long eflags,long esp,long ss) 5 { 6 struct task_struct *p; 7 int i; 8 struct file *f; 9 10 p = (struct task_struct *) get_free_page(); 11 if (!p) 12 return -EAGAIN; 13 task[nr] = p; 14 *p = *current; /* NOTE! this doesn't copy the supervisor stack */ 15 p->state = TASK_UNINTERRUPTIBLE; 16 p->pid = last_pid; 17 p->counter = p->priority; 18 p->signal = 0; 19 p->alarm = 0; 20 p->leader = 0; /* process leadership doesn't inherit */ 21 p->utime = p->stime = 0; 22 p->cutime = p->cstime = 0; 23 p->start_time = jiffies; 24 p->tss.back_link = 0; 25 p->tss.esp0 = PAGE_SIZE + (long) p; 26 p->tss.ss0 = 0x10; 27 p->tss.eip = eip; 28 p->tss.eflags = eflags; 29 p->tss.eax = 0; 30 p->tss.ecx = ecx; 31 p->tss.edx = edx; 32 p->tss.ebx = ebx; 33 p->tss.esp = esp; 34 p->tss.ebp = ebp; 35 p->tss.esi = esi; 36 p->tss.edi = edi; 37 p->tss.es = es & 0xffff; 38 p->tss.cs = cs & 0xffff; 39 p->tss.ss = ss & 0xffff; 40 p->tss.ds = ds & 0xffff; 41 p->tss.fs = fs & 0xffff; 42 p->tss.gs = gs & 0xffff; 43 p->tss.ldt = _LDT(nr); 44 p->tss.trace_bitmap = 0x80000000; 45 if (last_task_used_math == current) 46 __asm__("clts ; fnsave %0 ; frstor %0"::"m" (p->tss.i387)); 47 if (copy_mem(nr,p)) { 48 task[nr] = NULL; 49 free_page((long) p); 50 return -EAGAIN; 51 } 52 for (i=0; i<NR_OPEN;i++) 53 if (f=p->filp[i]) 54 f->f_count++; 55 if (current->pwd) 56 current->pwd->i_count++; 57 if (current->root) 58 current->root->i_count++; 59 if (current->executable) 60 current->executable->i_count++; 61 if (current->library) 62 current->library->i_count++; 63 set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); 64 set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); 65 p->p_pptr = current; 66 p->p_cptr = 0; 67 p->p_ysptr = 0; 68 p->p_osptr = current->p_cptr; 69 if (p->p_osptr) 70 p->p_osptr->p_ysptr = p; 71 current->p_cptr = p; 72 p->state = TASK_RUNNING; /* do this last, just in case */ 73 return last_pid; 74 }
其中复制父进程TSS中的PDBR(CR3)
另外注意哪些地址是物理地址,哪些地址是线性地址。
页目录项中的地址和页表项中的地址都是物理地址