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.

257 lines
7.4 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>
/*****************************/
#include <unistd.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)
{
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)) {
printk("free_page_tables: from copy_mem\n");
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 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");
*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)) {
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;
}
int sys_pthread_attr_init(pthread_attr_t* attr) /* ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD>pthread_attr_initʵ<74>ֺ<EFBFBD><D6BA><EFBFBD> */
{
if (!attr)
{
printk("Error:init pthread failed!\n");
sys_exit(0);
}
/* <20><><EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ַ<EFBFBD>ʹ<EFBFBD>С */
attr->state = 0;
attr->stackaddr = current->brk;
attr->stacksize = PAGE_SIZE;
return 0;
}
int thread_create(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;
/*******************************************/
long func_addr = ecx; /* ecx<63>д洢<D0B4><E6B4A2><EFBFBD><EFBFBD><EFBFBD>̴߳<DFB3><CCB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD><D0B5><EFBFBD>ʼ<EFBFBD><CABC>ַ<EFBFBD><D6B7>edx<64>д洢<D0B4><E6B4A2><EFBFBD>Ǵ<EFBFBD><C7B4>ݸ<EFBFBD><DDB8>̵߳IJ<CCB5><C4B2><EFBFBD> */
long func_arg = edx;
/*******************************************/
p = (struct task_struct*)get_free_page(); /*<2A><><EFBFBD><EFBFBD>һҳ<D2BB><D2B3><EFBFBD><EFBFBD>TCB*/
if (!p)
return -EAGAIN;
task[nr] = p;
*p = *current; /* NOTE! this doesn't copy the supervisor stack */
/*******************************************/
current->brk = current->brk + PAGE_SIZE; /*<2A><><EFBFBD><EFBFBD>ͬһ<CDAC><D2BB><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5>̹߳<DFB3><CCB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD>ַ<EFBFBD>ռ<D5BC><E4A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>TCB<43>ĵ<EFBFBD>ַ<EFBFBD>Լ<EFBFBD><D4BC><EFBFBD>ջ<EFBFBD><D5BB>ʼ<EFBFBD><CABC>ַ*/
p->start_stack = current->brk;
/*******************************************/
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 = func_addr; /* ecx<63>д洢<D0B4><E6B4A2><EFBFBD><EFBFBD><EFBFBD>̴߳<DFB3><CCB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>п<EFBFBD>ʼִ<CABC>еĵ<D0B5>ַ */
/*********************************************/
p->tss.eflags = eflags;
p->tss.eax = 0;
p->tss.ecx = ecx;
p->tss.edx = edx;
p->tss.ebx = ebx;
/*********************************************/
p->tss.esp = current->brk; /* ջ<><D5BB>ָ<EFBFBD><D6B8>Ӧ<EFBFBD>ȳ<EFBFBD>ʼ<EFBFBD><CABC>ΪΪ<CEAA>̶߳<DFB3>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ַ */
/*********************************************/
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 = current->tss.ldt; /* <20><><EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD><DFB3><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD>߳<EFBFBD>ldt<64><74>ַ<EFBFBD><D6B7>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD>̵<EFBFBD>ldt<64><74>ַ */
/*********************************************/
p->tss.trace_bitmap = 0x80000000;
if (last_task_used_math == current)
__asm__("clts ; fnsave %0"::"m" (p->tss.i387));
if (copy_mem(nr, p)) {
task[nr] = NULL;
free_page((long)p);
return -EAGAIN;
}
/*********************************************/
put_fs_long(func_arg, p->tss.esp); /* <20><>edx<64>д<EFBFBD>ŵIJ<C5B5><C4B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6B5BD><EFBFBD>̵߳Ķ<CCB5>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD> */
p->tss.esp -= 4; /* <20><><EFBFBD><EFBFBD><EFBFBD>˶<EFBFBD>ջָ<D5BB><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD><C6B6>ĸ<EFBFBD><C4B8>ֽڣ<D6BD><DAA3>Դ<EFBFBD>ŷ<EFBFBD><C5B7>ص<EFBFBD>ַ */
/*********************************************/
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;
return p->pid;
}