复制页目录项和页表的函数是
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)
另外注意哪些地址是物理地址,哪些地址是线性地址。
页目录项中的地址和页表项中的地址都是物理地址

