forever-learner 3 years ago
commit dcceacef1c

241
fork.c

@ -0,0 +1,241 @@
/*
* linux/kernel/fork.c
*
* (C) 1991 Linus Torvalds
*/
/*
* 'fork.c' contains the help-routines for the 'fork' system call
* (see also system_call.s), and some misc functions ('verify_area').
* Fork is rather simple, once you get the hang of it, but the memory
* management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
*/
#include <errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/system.h>
extern void write_verify(unsigned long address);
long last_pid=0;
void verify_area(void * addr,int size)
{
unsigned long start;
start = (unsigned long) addr;
size += start & 0xfff;
start &= 0xfffff000;
start += get_base(current->ldt[2]);
while (size>0) {
size -= 4096;
write_verify(start);
start += 4096;
}
}
int copy_mem(int nr,struct task_struct * p,int flag)
{
unsigned long old_data_base,new_data_base,data_limit;
unsigned long old_code_base,new_code_base,code_limit;
code_limit=get_limit(0x0f);
data_limit=get_limit(0x17);
old_code_base = get_base(current->ldt[1]);
old_data_base = get_base(current->ldt[2]);
if (old_data_base != old_code_base)
panic("We don't support separate I&D");
if (data_limit < code_limit)
panic("Bad data_limit");
new_data_base = new_code_base = nr * 0x4000000;
p->start_code = new_code_base;
set_base(p->ldt[1],new_code_base);
set_base(p->ldt[2],new_data_base);
if (copy_page_tables(old_data_base,new_data_base,data_limit,flag)) {
free_page_tables(new_data_base,data_limit);
return -ENOMEM;
}
return 0;
}
/*
* Ok, this is the main fork-routine. It copies the system process
* information (task[nr]) and sets up the necessary registers. It
* also copies the data segment in it's entirety.
*/
int copy_process(int flag,int nr,long ebp,long edi,long esi,long gs,long none,
long ebx,long ecx,long edx,
long fs,long es,long ds,
long eip,long cs,long eflags,long esp,long ss)
{
struct task_struct *p;
int i;
struct file *f;
p = (struct task_struct *) get_free_page();
if (!p)
return -EAGAIN;
task[nr] = p;
__asm__ volatile ("cld"); /* by wyj */
*p = *current; /* NOTE! this doesn't copy the supervisor stack */
p->state = TASK_UNINTERRUPTIBLE;
p->pid = last_pid;
p->father = current->pid;
p->counter = p->priority;
p->signal = 0;
p->alarm = 0;
p->leader = 0; /* process leadership doesn't inherit */
p->utime = p->stime = 0;
p->cutime = p->cstime = 0;
p->start_time = jiffies;
p->tss.back_link = 0;
p->tss.esp0 = PAGE_SIZE + (long) p;
p->tss.ss0 = 0x10;
p->tss.eip = eip;
p->tss.eflags = eflags;
p->tss.eax = 0;
p->tss.ecx = ecx;
p->tss.edx = edx;
p->tss.ebx = ebx;
p->tss.esp = esp;
p->tss.ebp = ebp;
p->tss.esi = esi;
p->tss.edi = edi;
p->tss.es = es & 0xffff;
p->tss.cs = cs & 0xffff;
p->tss.ss = ss & 0xffff;
p->tss.ds = ds & 0xffff;
p->tss.fs = fs & 0xffff;
p->tss.gs = gs & 0xffff;
p->tss.ldt = _LDT(nr);
p->tss.trace_bitmap = 0x80000000;
if (last_task_used_math == current)
__asm__("clts ; fnsave %0"::"m" (p->tss.i387));
if (copy_mem(nr,p,flag)) {
task[nr] = NULL;
free_page((long) p);
return -EAGAIN;
}
for (i=0; i<NR_OPEN;i++)
if (f=p->filp[i])
f->f_count++;
if (current->pwd)
current->pwd->i_count++;
if (current->root)
current->root->i_count++;
if (current->executable)
current->executable->i_count++;
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
p->state = TASK_RUNNING; /* do this last, just in case */
return last_pid;
}
int find_empty_process(void)
{
int i;
repeat:
if ((++last_pid)<0) last_pid=1;
for(i=0 ; i<NR_TASKS ; i++)
if (task[i] && task[i]->pid == last_pid) goto repeat;
for(i=1 ; i<NR_TASKS ; i++)
if (!task[i])
return i;
return -EAGAIN;
}
/*
esp
eipret 0xec8353c3 ps:0xc3
eipeipret
int (*fn)(void *) fnexit
*/
int do_clone(int nr,long tmp,int (*fn)(void *), void *child_stack, int flag)
{
//设置压栈表,方便操作;
long stack[1024];
unsigned long len=0;
task[nr]->tss.esp=(unsigned long) child_stack - 8;
stack[0] = (unsigned long) fn;
task[nr]->tss.eip = (unsigned long) child_stack - 4;
stack[1]= 0xec8353c3;
//栈区赋值;
len = 8;
char *p1=stack ,*p2=(char *)((unsigned long)child_stack-len);
while(len--)
put_fs_byte(*(p1++),p2++);
return 0;
}
/*
childstack
//子进程task[nr]的页表项获取目的是更新成child——stacK的物理页
nrfrom_page = ((address>>20) & 0xffc);
nrfrom_page += ((task[nr]->start_code>>20) & 0xffc);//页目录
nrfrom=*(unsigned long *)nrfrom_page; //页表项
if(!(nrfrom&1)) //无页表项分配一个
{
if(!(tpage=get_free_page()))
{
printk("out of memory.\n");
return -1;
}
else
{
*(unsigned long *)nrfrom_page= tpage | 7;
mem_map[(tpage-LOW_MEM)>>12]++;
}
}
nrfrom &= 0xfffff000;
nrfrom_page = nrfrom + ((address>>10) & 0xffc);
//获取child_stack的物理页,并将其复制给task[nr];
address=(unsigned long) child_stack;
from_page = ((address>>20) & 0xffc);
from_page += ((current->start_code>>20) & 0xffc);//页目录
if(!(*(unsigned long *)from_page&1)) //页表项不存在,申请页面
if(!(tpage=get_free_page()))
{
printk("out of memory.\n");
return -1;
}
else
{
*(unsigned long *)from_page= tpage | 7;
mem_map[(tpage-LOW_MEM)>>12]++;
}
from=*(unsigned long *)from_page; //页表项
from &= 0xfffff000;
from_page = from + ((address>>10) & 0xffc);
if(!(*(unsigned long *)from_page & 1)) //物理页不存在
if(!(tpage=get_free_page()))
{
printk("out of memory.\n");
return -1;
}
else
{
*(unsigned long *)from_page= tpage | 7;
mem_map[(tpage-LOW_MEM)>>12]++;
}
//复制给nr
*(unsigned long *)nrfrom_page = *(unsigned long *)from_page;
//更新esp,让其指向child_stack同样偏移的地点;
task[nr]->tss.esp=(unsigned long) child_stack;
//注意这里child_stack 指向的是高地址要向下面push.
unsigned long phy_addr = (*(unsigned long *)nrfrom_page & 0xfffff000) | ((unsigned long) child_stack & 0xfff);
if(argv)//参数列表不为空,将参数压入栈中,这里直接修改物理页
{
}
//char * tmp1=nrfrom, *tmp2=child_stack-1024,len=;
//while()
return 0;
}
*/

@ -36,7 +36,7 @@ void verify_area(void * addr,int size)
} }
} }
int copy_mem(int nr,struct task_struct * p) int copy_mem(int nr,struct task_struct * p,int flag)
{ {
unsigned long old_data_base,new_data_base,data_limit; unsigned long old_data_base,new_data_base,data_limit;
unsigned long old_code_base,new_code_base,code_limit; unsigned long old_code_base,new_code_base,code_limit;
@ -53,7 +53,7 @@ int copy_mem(int nr,struct task_struct * p)
p->start_code = new_code_base; p->start_code = new_code_base;
set_base(p->ldt[1],new_code_base); set_base(p->ldt[1],new_code_base);
set_base(p->ldt[2],new_data_base); set_base(p->ldt[2],new_data_base);
if (copy_page_tables(old_data_base,new_data_base,data_limit)) { if (copy_page_tables(old_data_base,new_data_base,data_limit,flag)) {
free_page_tables(new_data_base,data_limit); free_page_tables(new_data_base,data_limit);
return -ENOMEM; return -ENOMEM;
} }
@ -65,7 +65,7 @@ int copy_mem(int nr,struct task_struct * p)
* information (task[nr]) and sets up the necessary registers. It * information (task[nr]) and sets up the necessary registers. It
* also copies the data segment in it's entirety. * also copies the data segment in it's entirety.
*/ */
int copy_process(int nr,long ebp,long edi,long esi,long gs,long none, int copy_process(int flag,int nr,long ebp,long edi,long esi,long gs,long none,
long ebx,long ecx,long edx, long ebx,long ecx,long edx,
long fs,long es,long ds, long fs,long es,long ds,
long eip,long cs,long eflags,long esp,long ss) long eip,long cs,long eflags,long esp,long ss)
@ -113,7 +113,7 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
p->tss.trace_bitmap = 0x80000000; p->tss.trace_bitmap = 0x80000000;
if (last_task_used_math == current) if (last_task_used_math == current)
__asm__("clts ; fnsave %0"::"m" (p->tss.i387)); __asm__("clts ; fnsave %0"::"m" (p->tss.i387));
if (copy_mem(nr,p)) { if (copy_mem(nr,p,flag)) {
task[nr] = NULL; task[nr] = NULL;
free_page((long) p); free_page((long) p);
return -EAGAIN; return -EAGAIN;
@ -146,3 +146,96 @@ int find_empty_process(void)
return i; return i;
return -EAGAIN; return -EAGAIN;
} }
/*
esp
eipret 0xec8353c3 ps:0xc3
eipeipret
int (*fn)(void *) fnexit
*/
int do_clone(int nr,long tmp,int (*fn)(void *), void *child_stack, int flag)
{
//设置压栈表,方便操作;
long stack[1024];
unsigned long len=0;
task[nr]->tss.esp=(unsigned long) child_stack - 8;
stack[0] = (unsigned long) fn;
task[nr]->tss.eip = (unsigned long) child_stack - 4;
stack[1]= 0xec8353c3;
//栈区赋值;
len = 8;
char *p1=stack ,*p2=(char *)((unsigned long)child_stack-len);
while(len--)
put_fs_byte(*(p1++),p2++);
return 0;
}
/*
childstack
//子进程task[nr]的页表项获取目的是更新成child——stacK的物理页
nrfrom_page = ((address>>20) & 0xffc);
nrfrom_page += ((task[nr]->start_code>>20) & 0xffc);//页目录
nrfrom=*(unsigned long *)nrfrom_page; //页表项
if(!(nrfrom&1)) //无页表项分配一个
{
if(!(tpage=get_free_page()))
{
printk("out of memory.\n");
return -1;
}
else
{
*(unsigned long *)nrfrom_page= tpage | 7;
mem_map[(tpage-LOW_MEM)>>12]++;
}
}
nrfrom &= 0xfffff000;
nrfrom_page = nrfrom + ((address>>10) & 0xffc);
//获取child_stack的物理页,并将其复制给task[nr];
address=(unsigned long) child_stack;
from_page = ((address>>20) & 0xffc);
from_page += ((current->start_code>>20) & 0xffc);//页目录
if(!(*(unsigned long *)from_page&1)) //页表项不存在,申请页面
if(!(tpage=get_free_page()))
{
printk("out of memory.\n");
return -1;
}
else
{
*(unsigned long *)from_page= tpage | 7;
mem_map[(tpage-LOW_MEM)>>12]++;
}
from=*(unsigned long *)from_page; //页表项
from &= 0xfffff000;
from_page = from + ((address>>10) & 0xffc);
if(!(*(unsigned long *)from_page & 1)) //物理页不存在
if(!(tpage=get_free_page()))
{
printk("out of memory.\n");
return -1;
}
else
{
*(unsigned long *)from_page= tpage | 7;
mem_map[(tpage-LOW_MEM)>>12]++;
}
//复制给nr
*(unsigned long *)nrfrom_page = *(unsigned long *)from_page;
//更新esp,让其指向child_stack同样偏移的地点;
task[nr]->tss.esp=(unsigned long) child_stack;
//注意这里child_stack 指向的是高地址要向下面push.
unsigned long phy_addr = (*(unsigned long *)nrfrom_page & 0xfffff000) | ((unsigned long) child_stack & 0xfff);
if(argv)//参数列表不为空,将参数压入栈中,这里直接修改物理页
{
}
//char * tmp1=nrfrom, *tmp2=child_stack-1024,len=;
//while()
return 0;
}
*/

@ -64,7 +64,7 @@ nr_system_calls = 95 /* 72 */
* Ok, I get parallel printer interrupts while using the floppy for some * Ok, I get parallel printer interrupts while using the floppy for some
* strange reason. Urgel. Now I just ignore them. * strange reason. Urgel. Now I just ignore them.
*/ */
.globl system_call,sys_fork,timer_interrupt,sys_execve,sys_execve2 .globl system_call,sys_fork,timer_interrupt,sys_execve,sys_execve2,sys_clone
.globl hd_interrupt,floppy_interrupt,parallel_interrupt .globl hd_interrupt,floppy_interrupt,parallel_interrupt
.globl device_not_available, coprocessor_error .globl device_not_available, coprocessor_error
@ -227,8 +227,27 @@ sys_fork:
pushl %edi pushl %edi
pushl %ebp pushl %ebp
pushl %eax pushl %eax
pushl $0x0 #for flag
call copy_process call copy_process
addl $20,%esp addl $24,%esp #for flag
1: ret
.align 4
sys_clone:
call find_empty_process
testl %eax,%eax
js 1f
pushl %eax
push %gs
pushl %esi
pushl %edi
pushl %ebp
pushl %eax
pushl $0x1 #for flag
call copy_process
addl $24,%esp #for flag
call do_clone
addl $4,%esp
1: ret 1: ret
hd_interrupt: hd_interrupt:

@ -0,0 +1,317 @@
/*
* linux/kernel/system_call.s
*
* (C) 1991 Linus Torvalds
*/
/*
* system_call.s contains the system-call low-level handling routines.
* This also contains the timer-interrupt handler, as some of the code is
* the same. The hd- and flopppy-interrupts are also here.
*
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call. Ordinary interrupts
* don't handle signal-recognition, as that would clutter them up totally
* unnecessarily.
*
* Stack layout in 'ret_from_system_call':
*
* 0(%esp) - %eax
* 4(%esp) - %ebx
* 8(%esp) - %ecx
* C(%esp) - %edx
* 10(%esp) - %fs
* 14(%esp) - %es
* 18(%esp) - %ds
* 1C(%esp) - %eip
* 20(%esp) - %cs
* 24(%esp) - %eflags
* 28(%esp) - %oldesp
* 2C(%esp) - %oldss
*/
SIG_CHLD = 17
EAX = 0x00
EBX = 0x04
ECX = 0x08
EDX = 0x0C
FS = 0x10
ES = 0x14
DS = 0x18
EIP = 0x1C
CS = 0x20
EFLAGS = 0x24
OLDESP = 0x28
OLDSS = 0x2C
state = 0 # these are offsets into the task-struct.
counter = 4
priority = 8
signal = 12
sigaction = 16 # MUST be 16 (=len of sigaction)
blocked = (33*16)
# offsets within sigaction
sa_handler = 0
sa_mask = 4
sa_flags = 8
sa_restorer = 12
nr_system_calls = 95 /* 72 */
/*
* Ok, I get parallel printer interrupts while using the floppy for some
* strange reason. Urgel. Now I just ignore them.
*/
.globl system_call,sys_fork,timer_interrupt,sys_execve,sys_execve2,sys_clone
.globl hd_interrupt,floppy_interrupt,parallel_interrupt
.globl device_not_available, coprocessor_error
.align 4
bad_sys_call:
movl $-1,%eax
iret
.align 4
reschedule:
pushl $ret_from_sys_call
jmp schedule
.align 4
system_call:
cmpl $nr_system_calls-1,%eax
ja bad_sys_call
push %ds
push %es
push %fs
pushl %edx
pushl %ecx # push %ebx,%ecx,%edx as parameters
pushl %ebx # to the system call
movl $0x10,%edx # set up ds,es to kernel space
mov %dx,%ds
mov %dx,%es
movl $0x17,%edx # fs points to local data space
mov %dx,%fs
pushl %eax #by wyj
call print_nr
popl %eax
call sys_call_table(,%eax,4)
pushl %eax
movl current,%eax
cmpl $0,state(%eax) # state
jne reschedule
cmpl $0,counter(%eax) # counter
je reschedule
ret_from_sys_call:
movl current,%eax # task[0] cannot have signals
cmpl task,%eax
je 3f
cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
jne 3f
cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
jne 3f
movl signal(%eax),%ebx
movl blocked(%eax),%ecx
notl %ecx
andl %ebx,%ecx
bsfl %ecx,%ecx
je 3f
btrl %ecx,%ebx
movl %ebx,signal(%eax)
incl %ecx
pushl %ecx
call do_signal
popl %eax
3: popl %eax
popl %ebx
popl %ecx
popl %edx
pop %fs
pop %es
pop %ds
iret
.align 4
coprocessor_error:
push %ds
push %es
push %fs
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
pushl $ret_from_sys_call
jmp math_error
.align 2
device_not_available:
push %ds
push %es
push %fs
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
pushl $ret_from_sys_call
clts # clear TS so that we can use math
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
je math_state_restore
pushl %ebp
pushl %esi
pushl %edi
call math_emulate
popl %edi
popl %esi
popl %ebp
ret
.align 4
timer_interrupt:
push %ds # save ds,es and put kernel data space
push %es # into them. %fs is used by _system_call
push %fs
pushl %edx # we save %eax,%ecx,%edx as gcc doesn't
pushl %ecx # save those across function calls. %ebx
pushl %ebx # is saved as we use that in ret_sys_call
pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
incl jiffies
movb $0x20,%al # EOI to interrupt controller #1
outb %al,$0x20
movl CS(%esp),%eax
andl $3,%eax # %eax is CPL (0 or 3, 0=supervisor)
pushl %eax
call do_timer # 'do_timer(long CPL)' does everything from
addl $4,%esp # task switching to accounting ...
jmp ret_from_sys_call
.align 4
sys_execve:
lea EIP(%esp),%eax
pushl %eax
call do_execve
addl $4,%esp
ret
.align 4
sys_execve2:
lea EIP(%esp),%eax
pushl %eax
call do_execve2
addl $4,%esp
ret
.align 4
sys_fork:
call find_empty_process
testl %eax,%eax
js 1f
push %gs
pushl %esi
pushl %edi
pushl %ebp
pushl %eax
pushl $0x0 #for flag
call copy_process
addl $24,%esp #for flag
1: ret
.align 4
sys_clone:
call find_empty_process
testl %eax,%eax
js 1f
pushl %eax
push %gs
pushl %esi
pushl %edi
pushl %ebp
pushl %eax
pushl $0x1 #for flag
call copy_process
addl $24,%esp #for flag
call do_clone
addl $4,%esp
1: ret
hd_interrupt:
pushl %eax
pushl %ecx
pushl %edx
push %ds
push %es
push %fs
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
movb $0x20,%al
outb %al,$0xA0 # EOI to interrupt controller #1
jmp 1f # give port chance to breathe
1: jmp 1f
1: xorl %edx,%edx
xchgl do_hd,%edx
testl %edx,%edx
jne 1f
movl $unexpected_hd_interrupt,%edx
1: outb %al,$0x20
call *%edx # "interesting" way of handling intr.
pop %fs
pop %es
pop %ds
popl %edx
popl %ecx
popl %eax
iret
floppy_interrupt:
pushl %eax
pushl %ecx
pushl %edx
push %ds
push %es
push %fs
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
movl $0x17,%eax
mov %ax,%fs
movb $0x20,%al
outb %al,$0x20 # EOI to interrupt controller #1
xorl %eax,%eax
xchgl do_floppy,%eax
testl %eax,%eax
jne 1f
movl $unexpected_floppy_interrupt,%eax
1: call *%eax # "interesting" way of handling intr.
pop %fs
pop %es
pop %ds
popl %edx
popl %ecx
popl %eax
iret
parallel_interrupt:
pushl %eax
movb $0x20,%al
outb %al,$0x20
popl %eax
iret
Loading…
Cancel
Save