diff options
Diffstat (limited to 'src/kernel/fork.c')
-rw-r--r-- | src/kernel/fork.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/kernel/fork.c b/src/kernel/fork.c new file mode 100644 index 0000000..018a501 --- /dev/null +++ b/src/kernel/fork.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * linux/kernel/fork.c | ||
3 | * | ||
4 | * (C) 1991 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * 'fork.c' contains the help-routines for the 'fork' system call | ||
9 | * (see also system_call.s), and some misc functions ('verify_area'). | ||
10 | * Fork is rather simple, once you get the hang of it, but the memory | ||
11 | * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' | ||
12 | */ | ||
13 | #include <string.h> | ||
14 | #include <errno.h> | ||
15 | |||
16 | #include <linux/sched.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <asm/segment.h> | ||
19 | #include <asm/system.h> | ||
20 | |||
21 | extern void write_verify(unsigned long address); | ||
22 | |||
23 | long last_pid=0; | ||
24 | |||
25 | void verify_area(void * addr,int size) | ||
26 | { | ||
27 | unsigned long start; | ||
28 | |||
29 | start = (unsigned long) addr; | ||
30 | size += start & 0xfff; | ||
31 | start &= 0xfffff000; | ||
32 | start += get_base(current->ldt[2]); | ||
33 | while (size>0) { | ||
34 | size -= 4096; | ||
35 | write_verify(start); | ||
36 | start += 4096; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | int copy_mem(int nr,struct task_struct * p) | ||
41 | { | ||
42 | unsigned long old_data_base,new_data_base,data_limit; | ||
43 | unsigned long old_code_base,new_code_base,code_limit; | ||
44 | |||
45 | code_limit=get_limit(0x0f); | ||
46 | data_limit=get_limit(0x17); | ||
47 | old_code_base = get_base(current->ldt[1]); | ||
48 | old_data_base = get_base(current->ldt[2]); | ||
49 | if (old_data_base != old_code_base) | ||
50 | panic("We don't support separate I&D"); | ||
51 | if (data_limit < code_limit) | ||
52 | panic("Bad data_limit"); | ||
53 | new_data_base = new_code_base = nr * 0x4000000; | ||
54 | p->start_code = new_code_base; | ||
55 | set_base(p->ldt[1],new_code_base); | ||
56 | set_base(p->ldt[2],new_data_base); | ||
57 | if (copy_page_tables(old_data_base,new_data_base,data_limit)) { | ||
58 | printk("free_page_tables: from copy_mem\n"); | ||
59 | free_page_tables(new_data_base,data_limit); | ||
60 | return -ENOMEM; | ||
61 | } | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * Ok, this is the main fork-routine. It copies the system process | ||
67 | * information (task[nr]) and sets up the necessary registers. It | ||
68 | * also copies the data segment in it's entirety. | ||
69 | */ | ||
70 | int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, | ||
71 | long ebx,long ecx,long edx, | ||
72 | long fs,long es,long ds, | ||
73 | long eip,long cs,long eflags,long esp,long ss) | ||
74 | { | ||
75 | struct task_struct *p; | ||
76 | int i; | ||
77 | struct file *f; | ||
78 | |||
79 | p = (struct task_struct *) get_free_page(); | ||
80 | if (!p) | ||
81 | return -EAGAIN; | ||
82 | task[nr] = p; | ||
83 | |||
84 | // NOTE!: the following statement now work with gcc 4.3.2 now, and you | ||
85 | // must compile _THIS_ memcpy without no -O of gcc.#ifndef GCC4_3 | ||
86 | *p = *current; /* NOTE! this doesn't copy the supervisor stack */ | ||
87 | p->state = TASK_UNINTERRUPTIBLE; | ||
88 | p->pid = last_pid; | ||
89 | p->father = current->pid; | ||
90 | p->counter = p->priority; | ||
91 | p->signal = 0; | ||
92 | p->alarm = 0; | ||
93 | p->leader = 0; /* process leadership doesn't inherit */ | ||
94 | p->utime = p->stime = 0; | ||
95 | p->cutime = p->cstime = 0; | ||
96 | p->start_time = jiffies; | ||
97 | p->tss.back_link = 0; | ||
98 | p->tss.esp0 = PAGE_SIZE + (long) p; | ||
99 | p->tss.ss0 = 0x10; | ||
100 | p->tss.eip = eip; | ||
101 | p->tss.eflags = eflags; | ||
102 | p->tss.eax = 0; | ||
103 | p->tss.ecx = ecx; | ||
104 | p->tss.edx = edx; | ||
105 | p->tss.ebx = ebx; | ||
106 | p->tss.esp = esp; | ||
107 | p->tss.ebp = ebp; | ||
108 | p->tss.esi = esi; | ||
109 | p->tss.edi = edi; | ||
110 | p->tss.es = es & 0xffff; | ||
111 | p->tss.cs = cs & 0xffff; | ||
112 | p->tss.ss = ss & 0xffff; | ||
113 | p->tss.ds = ds & 0xffff; | ||
114 | p->tss.fs = fs & 0xffff; | ||
115 | p->tss.gs = gs & 0xffff; | ||
116 | p->tss.ldt = _LDT(nr); | ||
117 | p->tss.trace_bitmap = 0x80000000; | ||
118 | if (last_task_used_math == current) | ||
119 | __asm__("clts ; fnsave %0"::"m" (p->tss.i387)); | ||
120 | if (copy_mem(nr,p)) { | ||
121 | task[nr] = NULL; | ||
122 | free_page((long) p); | ||
123 | return -EAGAIN; | ||
124 | } | ||
125 | for (i=0; i<NR_OPEN;i++) | ||
126 | if ((f=p->filp[i])) | ||
127 | f->f_count++; | ||
128 | if (current->pwd) | ||
129 | current->pwd->i_count++; | ||
130 | if (current->root) | ||
131 | current->root->i_count++; | ||
132 | if (current->executable) | ||
133 | current->executable->i_count++; | ||
134 | set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); | ||
135 | set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt)); | ||
136 | p->state = TASK_RUNNING; /* do this last, just in case */ | ||
137 | return last_pid; | ||
138 | } | ||
139 | |||
140 | int find_empty_process(void) | ||
141 | { | ||
142 | int i; | ||
143 | |||
144 | repeat: | ||
145 | if ((++last_pid)<0) last_pid=1; | ||
146 | for(i=0 ; i<NR_TASKS ; i++) | ||
147 | if (task[i] && task[i]->pid == last_pid) goto repeat; | ||
148 | for(i=1 ; i<NR_TASKS ; i++) | ||
149 | if (!task[i]) | ||
150 | return i; | ||
151 | return -EAGAIN; | ||
152 | } | ||