linux0.12 复制页目录项和页表

复制页目录项和页表的函数是

 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)

另外注意哪些地址是物理地址,哪些地址是线性地址。

页目录项中的地址和页表项中的地址都是物理地址

 

你可能感兴趣的:(linux)