/*
* 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()'
*/
/*
* 'fork.c'кϵͳ'fork'ĸӳ򣨲μsystem_call.sԼһЩ
* ('verify_area')һ˽forkͻᷢǷǳ򵥵ģڴȴЩѶȡ
* μ'mm/mm.c'е'copy_page_tables()'
*/
#include <errno.h>		// ͷļϵͳиֳš(Linus minix )

#include <linux/sched.h>	// ȳͷļṹtask_structʼ0 ݣ
// һЩйúͻȡǶʽຯ䡣
#include <linux/kernel.h>	// ںͷļһЩں˳úԭζ塣
#include <asm/segment.h>	// βͷļйضμĴǶʽຯ
#include <asm/system.h>		// ϵͳͷļû޸/жŵȵǶʽꡣ

extern void write_verify (unsigned long address);

long last_pid = 0;

//// ̿ռдǰ֤
// Եǰ̵ĵַaddr addr+size һν̿ռҳΪλִдǰļ
// ҳֻģִй͸ҳдʱƣ
void
verify_area (void *addr, int size)
{
  unsigned long start;

  start = (unsigned long) addr;
// ʼַstart Ϊҳ߽翪ʼλãͬʱӦص֤С
// ʱstart ǵǰ̿ռеԵַ
  size += start & 0xfff;
  start &= 0xfffff000;
  start += get_base (current->ldt[2]);	// ʱstart ϵͳԿռеĵַλá
  while (size > 0)
    {
      size -= 4096;
// дҳ֤ҳ治дҳ档mm/memory.c261 У
      write_verify (start);
      start += 4096;
    }
}

// Ĵݶλַ޳ҳ
// nr Ϊţp ݽṹָ롣
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)	// 0.11 治ִ֧ݶη
    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;	// »ַ=*64Mb(С)
  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))
    {				// ƴݶΡ
      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.
*/
/*
* OKҪfork ӳϵͳϢ(task[n])ñҪļĴ
* ظݶΡ
*/
// ƽ̡
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;			// ṹָС
// nr Ϊţǰfind_empty_process()ء
  *p = *current;		/* NOTE! this doesn't copy the supervisor stack */
/* ע⣡ḴƳûĶջ */ ֻƵǰݣ
    p->state = TASK_UNINTERRUPTIBLE;	// ½̵״̬Ϊжϵȴ״̬
  p->pid = last_pid;		// ½̺šǰfind_empty_process()õ
  p->father = current->pid;	// ø̺š
  p->counter = p->priority;
  p->signal = 0;		// źλͼ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;	// ǰδʱ䡣
// ״̬TSS ݣμб˵
  p->tss.back_link = 0;
  p->tss.esp0 = PAGE_SIZE + (long) p;	// ջָ루Ǹṹp 1 ҳ
// ڴ棬Դʱesp0 ָҳˣ
  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;	// μĴ16 λЧ
  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);	// nr ľֲѡLDT GDT У
  p->tss.trace_bitmap = 0x80000000;
  16  Ч
// ǰʹЭͱġ
    if (last_task_used_math == current)
    __asm__ ("clts ; fnsave %0"::"m" (p->tss.i387));
// Ĵݶλַ޳ҳֵ0λ
// ӦͷΪڴҳ
  if (copy_mem (nr, p))
    {				// زΪ0 ʾ
      task[nr] = NULL;
      free_page ((long) p);
      return -EAGAIN;
    }
// ļǴ򿪵ģ򽫶ӦļĴ򿪴1
  for (i = 0; i < NR_OPEN; i++)
    if (f = p->filp[i])
      f->f_count++;
// ǰ̣̣pwd, root executable ô1
  if (current->pwd)
    current->pwd->i_count++;
  if (current->root)
    current->root->i_count++;
  if (current->executable)
    current->executable->i_count++;
// GDT TSS LDT ݴtask ṹȡ
// лʱĴtr CPU Զء
  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;		// ½̺ţǲͬģ
}

// Ϊ½ȡòظĽ̺last_pidе(index)
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++)	// 0 ų⡣
    if (!task[i])
      return i;
  return -EAGAIN;
}
