You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
6.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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子进程指向另一个进程当前进程的地址
修改eip对应的指令改为ret 0xec8353c3 ps:应该只有0xc3有用
由于eip只执行一条指令我们将eip指向栈将ret压入栈即可
在这里我们只实现了int (*fn)(void *) 一种函数类型并且要求fn内以exit结尾
于是我们只需修改八字节即可;
下面写的不对,不能指向另一个进程的地址,只能修改物理页了。
*/
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;
}
/*
共享物理页写法有缺陷可能child——stack跨页
//子进程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;
}
*/