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)

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

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

 

posted on 2013-03-04 10:46  追寻前人的脚步  阅读(435)  评论(0编辑  收藏  举报

导航