Linux0.11 paging


本文修改Linux0.11源码内核空间虚拟地址为0xC0000000,用户虚拟空间为0x00000000-0xC0000000共3G的虚拟空间,已经在bochs和qemu测试通过,成功进入shell

参考了更高版本的Linux源码,

diff --git a/Makefile b/Makefile
index 38f9fff..ef2db9f 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a
 MATH    =kernel/math/math.a
 LIBS    =lib/lib.a
 
-all: clean Image
+all: Image
 Image: boot/bootsect boot/setup kernel.bin FORCE
     $(BUILD) boot/bootsect boot/setup kernel.bin Image
     $(Q)rm -f kernel.bin
diff --git a/boot/head.s b/boot/head.s
index d2cbe2b..26540f3 100644
--- a/boot/head.s
+++ b/boot/head.s
@@ -1,84 +1,55 @@
 /*
  *  linux/boot/head.s
  *
- *  (C) 1991  Linus Torvalds
+ *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+.code32
 /*
  *  head.s contains the 32-bit startup code.
  *
  * NOTE!!! Startup happens at absolute address 0x00000000, which is also where
  * the page directory will exist. The startup code will be overwritten by
  * the page directory.
- *
- * head被链接至system的开始位置,地址为0
- *
  */
 .text
-.globl idt,gdt,pg_dir,tmp_floppy_area
-pg_dir:
-.globl startup_32
-
-/* 
- * 根据setup模块我们安装了两个段描述符,分别是代码段和数据段,共8MB的空间
- * 0x10的二进制为10000, 我们可以看出DPL为0,T为0表示此描述符在全局描述符中的第二个描述符,权限为0最高权限
- * 设置数据段为0x10,全局描述第2个段
+.globl startup_32,idt,gdt,pg_dir,tmp_floppy_area,floppy_track_buffer
+/*
+ * swapper_pg_dir is the main page directory, address 0x00000000
  */
+pg_dir:
 startup_32:
+    cld
     movl $0x10,%eax
     mov %ax,%ds
     mov %ax,%es
     mov %ax,%fs
     mov %ax,%gs
-    /*
-     * 设置栈顶指针
-     *
-     * 设置栈顶指针
-     *
-     * stack_start定义在kernel/sched.c中
-     * long user_stack[PAGE_SIZE >> 2];
-     * struct {
-     *   long *a;
-     *   short b;
-     * } stack_start { &user_stack, 0x10}
-     * lss设置了栈顶指针和其栈的段地址,0x10表示数据段,地址为stack_start定义起大小为PAGE_SIZE>>2 = 1024字节
-     *
-     */
     lss stack_start,%esp
     call setup_idt
-    call setup_gdt
-
-    /*
-     * 重新设置数据段,因为在上面的程序中修改gdt,因此需要重新加载,
-     */
-    movl $0x10,%eax            # reload all the segment registers
-    mov %ax,%ds                # after changing gdt. CS was already
-    mov %ax,%es                # reloaded in 'setup_gdt'
-    mov %ax,%fs
-    mov %ax,%gs
-    lss stack_start,%esp
-    /*
-     * xorl为异或运算,相同为0,不同为1,此处的意思是清零寄存器
-     */
+    
     xorl %eax,%eax
 1:    incl %eax                # check that A20 really IS enabled
     movl %eax,0x000000        # loop forever if it isn't
     cmpl %eax,0x100000
     je 1b
+    
+
+/* 
+ * NOTE! 486 should set bit 16, to check for write-protect in supervisor 
+ * mode. Then it would be unnecessary with the "verify_area()"-calls. 
+ * 486 users probably want to set the NE (#5) bit also, so as to use 
+ * int 16 for math errors. 
+ */    
+
+ movl %cr0,%eax            # check math chip    
+ andl $0x80000011,%eax    # Save PG,PE,ET
+ /* "orl $0x10020,%eax" here for 486 might be good */    
+ orl $2,%eax            # set MP    
+ movl %eax,%cr0    
+ call check_x87    
+ jmp after_page_tables
 
-/*
- * NOTE! 486 should set bit 16, to check for write-protect in supervisor
- * mode. Then it would be unnecessary with the "verify_area()"-calls.
- * 486 users probably want to set the NE (#5) bit also, so as to use
- * int 16 for math errors.
- */
-    movl %cr0,%eax            # check math chip
-    andl $0x80000011,%eax    # Save PG,PE,ET
-/* "orl $0x10020,%eax" here for 486 might be good */
-    orl $2,%eax                # set MP
-    movl %eax,%cr0
-    call check_x87
-    jmp after_page_tables
 
 /*
  * We depend on ET to be correct. This checks for 287/387.
@@ -87,79 +58,40 @@ check_x87:
     fninit
     fstsw %ax
     cmpb $0,%al
-    je 1f                    /* no coprocessor: have to set bits */
-    movl %cr0,%eax
-    xorl $6,%eax            /* reset MP, set EM */
+    je 1f
+    movl %cr0,%eax        /* no coprocessor: have to set bits */
+    xorl $6,%eax        /* reset MP, set EM */
     movl %eax,%cr0
     ret
 .align 2
-1:    .byte 0xDB,0xE4            /* fsetpm for 287, ignored by 387 */
+1:    .byte 0xDB,0xE4        /* fsetpm for 287, ignored by 387 */
     ret
 
 /*
  *  setup_idt
  *
  *  sets up a idt with 256 entries pointing to
- *  ignore_int, interrupt gates. It then loads
- *  idt. Everything that wants to install itself
- *  in the idt-table may do so themselves. Interrupts
+ *  ignore_int, interrupt gates. It doesn't actually load
+ *  idt - that can be done only after paging has been enabled
+ *  and the kernel moved to 0xC0000000. Interrupts
  *  are enabled elsewhere, when we can be relatively
  *  sure everything is ok. This routine will be over-
  *  written by the page tables.
  */
-/* 
- *
- * setup_idt会将256个中断向量设置为ignore_int, lea执行为取有效地址指令
- *
- */
 setup_idt:
-    lea ignore_int,%edx     /* address of edx */
-    movl $0x00080000,%eax   /* EAX is interrupt gat Blow 32bit */
-    movw %dx,%ax            /* selector = 0x0008 = cs */
-    movw $0x8E00,%dx        /* interrupt gate - dpl=0, present */
-                            /* P = 1, DPL=00 D = 1, 32bits */
-                            /* type = 110 interrupt gate */
+    lea ignore_int,%edx
+    movl $0x00080000,%eax
+    movw %dx,%ax        /* selector = 0x0008 = cs */
+    movw $0x8E00,%dx    /* interrupt gate - dpl=0, present */
 
-    /***********************************************************************************************
-    use EAX for interrupt description blow 32bit
-    Use EDX for interrupt descirpt high 32bit
-    EAX存放的是中断描述符的低32位
-    EAX存放的是中断描述符的高32位
-    上述的代码是将中断服务子程序处理成如下格式, CS为8表示二进制为00001000表示段选择子为1(代码段)
-    +----------+---+-----------+---+---+-----------+--------+--------------+-----------+----------+
-    | H 16bits | P | DPL(2bit) | 0 | D | 3bit type | 3bit 0 | 5bit Reserve | 16bits CS | L 16bits |
-    +----------+---+-----------+---+---+-----------+--------+--------------+-----------+----------+
-    |          | 1 |   00      | 0 | 1 |    110    |   000  |              |     8     |          |
-    +----------+---+-----------+---+---+-----------+--------+--------------+-----------+----------+
-    *************************************************************************************************/
-    
-    lea idt,%edi            /*将中断描述符表的地址存放在edi寄存器中,一般作为目的地址寄存器*/
-    mov $256,%ecx           /*计数寄存器,一共256项*/
-    
-    /* 如下代码将中断描述符复制到edi寄存器的地址处,并循环256次
-     * 使用lidt加载idt_descr的中断描述符
-     */    
+    lea idt,%edi
+    mov $256,%ecx
 rp_sidt:
-    movl %eax,(%edi)        /* *edi == eax */
-    movl %edx,4(%edi)       /* *(edi + 4) = eds */
-    addl $8,%edi            /* edi = edi + 8, meas next interrupt select descript */
-    dec %ecx                /* ecs -- */
-    jne rp_sidt             /* if not 0 goto rp_sidt */
-    lidt idt_descr          /* load interrupt select descript */
-    ret
-
-/*
- *  setup_gdt
- *
- *  This routines sets up a new gdt and loads it.
- *  Only two entries are currently built, the same
- *  ones that were built in init.s. The routine
- *  is VERY complicated at two whole lines, so this
- *  rather long comment is certainly needed :-).
- *  This routine will beoverwritten by the page tables.
- */
-setup_gdt:
-    lgdt gdt_descr
+    movl %eax,(%edi)
+    movl %edx,4(%edi)
+    addl $8,%edi
+    dec %ecx
+    jne rp_sidt
     ret
 
 /*
@@ -180,6 +112,8 @@ pg2:
 pg3:
 
 .org 0x5000
+
+
 /*
  * tmp_floppy_area is used by the floppy-driver when DMA cannot
  * reach to a buffer-block. It needs to be aligned, so that it isn't
@@ -187,28 +121,41 @@ pg3:
  */
 tmp_floppy_area:
     .fill 1024,1,0
-
-/* 
- * 程序运行到此处时会调用了setup_paging在setup_paging返回时由于将main函数进行压堆栈将执行main函数
- * L6的地址为main函数的返回地址
- * $1, $2, $3为main函数的参数
+/*
+ * floppy_track_buffer is used to buffer one track of floppy data: it
+ * has to be separate from the tmp_floppy area, as otherwise a single-
+ * sector read/write can mess it up. It can contain one full track of
+ * data (18*2*512 bytes).
  */
+floppy_track_buffer:
+    .fill 512*2*18,1,0
+
 after_page_tables:
-    pushl $1        # These are the parameters to main :-)
-    pushl $2
-    pushl $3
-    pushl $L6        # return address for main, if it decides to.
-    pushl $main
-    jmp setup_paging
+    call setup_paging
+    lgdt gdt_descr
+    lidt idt_descr
+    ljmp $0x08,$1f
+1:    movl $0x10,%eax        # reload all the segment registers
+    mov %ax,%ds        # after changing gdt.
+    mov %ax,%es
+    mov %ax,%fs
+    mov %ax,%gs
+    lss stack_start,%esp
+    pushl $0        # These are the parameters to main :-)
+    pushl $0
+    pushl $0
+    cld            # gcc2 wants the direction flag cleared at all times
+    call main
 L6:
     jmp L6            # main should never return here, but
-                    # just in case, we know what happens.
+                # just in case, we know what happens.
 
 /* This is the default interrupt "handler" :-) */
 int_msg:
     .asciz "Unknown interrupt\n\r"
 .align 2
 ignore_int:
+    cld
     pushl %eax
     pushl %ecx
     pushl %edx
@@ -257,152 +204,64 @@ ignore_int:
  */
 .align 2
 setup_paging:
-    movl $1024*5,%ecx            /* 5 pages - pg_dir+4 page tables */
-    xorl %eax,%eax              /* EAX is 0 */
-    xorl %edi,%edi                /* pg_dir is at 0x000, EDI is 0, start address*/
-    cld;rep;stosl               /* stosl *EDI = EAX */
-    /**********************************************************************
-    以上代码的意思是从0-1024*5的地址空间清零,由于此时0地址处的代码已经执行完毕没有什么用了
-    为什么是1024*5的长度呢,我们在上面的代码中可以看到.org 0x1000 pg0: 从0x1000为第一个页表一共建立了4个
-    在加上0地址到0x1000一共5个
-    问题1:分段是怎么用的?
-    答:执行发出逻辑地址后经分段部件形成线性地址,根据前面的分析我们支持逻辑地址等于线性地址
-    问题2:分页是怎么进行地址映射的?
-    答:分页机制将线性地址分成三个部分进行查表,高10位表示页表目录,中10位表示页表项,低12位表示偏移,在寻址时
-    根据高10位找到页表目录,页表目录存放了页表的起始地址,根据中10位在页面中找到对应的物理页,在加上低12位的偏移形成物理地址
-    页表目录和页表的格式如下(页表目录和页表是4KB对齐的):
-    +----------------------------------------------+---------------------+ 
-    |页表目录或者页表物理地址的高位BIT(12-31)      |          7          | 
-    +----------------------------------------------+---------------------+  
-    由于页表目录和页表以4KB对齐,因此我们不用关心其低12位,低12位有其特殊的意义,具体可查询intel的数据手册
-
-    pg_dir表示页表的地址,7表示为该页存在用户可读可写
-    由于目前系统的最大内存为16MB,因此只用到也变目录的前4项(为什么)
-    一个页表管理1024项4KB的地址空间既4MB,那么16MB需要多少个页表目录呢,答案是4个
-    ***********************************************************************/
-    
+    movl $1024*5,%ecx            /* 5 pages - swapper_pg_dir+4 page tables */
+    xorl %eax,%eax
+    xorl %edi,%edi                /* swapper_pg_dir is at 0x000 */
+    cld;rep;stosl
+    
+    /* Identity-map the kernel in low 4MB memory for ease of transition */
     movl $pg0+7,pg_dir            /* set present bit/user r/w */
-    movl $pg1+7,pg_dir+4        /*  --------- " " --------- */
-    movl $pg2+7,pg_dir+8        /*  --------- " " --------- */
-    movl $pg3+7,pg_dir+12        /*  --------- " " --------- */
-
-    /*
-     上面的代码执行完毕后内存如下
-    --起始地址0x0000
-        0x00001 007
-        0x00002 007
-        0x00003 007
-        0x00004 007
-    一共四项页表目录
-    */
-     
-    movl $pg3+4092,%edi         /* end of this page */
-    movl $0xfff007,%eax            /* 16Mb - 4096 + 7 (r/w user,p) */
-    std                         /* derection -4 */
-1:    stosl                        /* fill pages backwards - more efficient :-) *EDI=EAS */
+    movl $pg1+7,pg_dir+4        /* set present bit/user r/w */
+    movl $pg2+7,pg_dir+8        /* set present bit/user r/w */
+    movl $pg3+7,pg_dir+12        /* set present bit/user r/w */
+    
+    /* But the real place is at 0xC0000000 */
+    movl $pg0+7,pg_dir+3072        /* set present bit/user r/w */
+    movl $pg1+7,pg_dir+3076        /*  --------- " " --------- */
+    movl $pg2+7,pg_dir+3080        /*  --------- " " --------- */
+    movl $pg3+7,pg_dir+3084        /*  --------- " " --------- */
+    
+    movl $pg3+4092,%edi
+    movl $0xfff007,%eax            /*  16Mb - 4096 + 7 (r/w user,p) */
+    std
+1:    stosl                        /* fill pages backwards - more efficient :-) */
     subl $0x1000,%eax
     jge 1b
     cld
-    /*
-    以上的代码倒序从pg3的最后一项开始填充直到eax为0,这样填充下来后如下图
-        页表目录
-        -------------------------0x0000
-        0x00001 007
-        -------------------------0x0004
-        0x00002 007
-        -------------------------0x0008
-        0x00003 007
-        -------------------------0x000C
-        0x00004 007
-        ...
-        ...
-        ...
-      pg0页表0
-        -------------------------0x1000
-        0x00000 007
-        -------------------------0x1004
-        0x00001 007
-        -------------------------0x1008
-        ...
-        ...
-        ...
-      pg1页表1
-        -------------------------0x2000
-        0x00400 007
-        -------------------------0x2004
-        0x00401 007
-        -------------------------0x2008
-        ...
-        ...
-        ...
-      pg2页表2
-        -------------------------0x3000
-        0x00800 007
-        -------------------------0x3004
-        0x00801 007
-        -------------------------0x3008
-        ...
-        ...
-        ...
-      pg3页表3
-        -------------------------0x4000
-        0x00c00 007
-        -------------------------0x4004
-        0x00c01 007
-        -------------------------0x4008
-        ...
-        ...
-        ...
-        -------------------------0x4ff4
-        0x00ffd 007
-        -------------------------0x4ff8
-        0x00ffe 007
-        -------------------------0x4ffc
-        0x00fff 007
-        -------------------------0x5000
-    我们举一个例子,如果要访问0x00401555地址处的数据,我们知道系统需先经过段映射由于段映射后线性地址和逻辑地址一样
-    因此访问的地址还是0x00401555,段映射后需要进行页映射,我们根据上面的问题2对地址进行分解
-    0x00401555的高10位为1寻找第一个页表目录值为0x00002 007,中10位为1在页表1中的第一项值为0x00401 007,低12位为555,
-    根据0x00401 007去掉007,再加上555,最终的地址为0x00401555,我们发现饶了一圈逻辑地址和物理地址一样
-    这种映射方式成为平坦映射
-    
-    我们再来一个例子,地址0x00FFF111地址,我们根据规则将其分解
-    高10位为0000000011即3,第三项页面目录项其对应的页面项为4,对应的地址为3*4=12, 0x0c
-    中10位为1111111111即1023,每一个页面占4个地址即1023*4 = 4092 = 0xFFC
-    低12位为111
-    如上面蓝色字体的映射过程,其最终地址还是0x00fff111
-    我们可以看出页管理后系统还是平坦映射,从0地址开始一共16MB
-    */
-
-    
-    xorl %eax,%eax                /* pg_dir is at 0x0000 */
+    xorl %eax,%eax                /* swapper_pg_dir is at 0x0000 */
     movl %eax,%cr3                /* cr3 - page directory start */
     movl %cr0,%eax
     orl $0x80000000,%eax
     movl %eax,%cr0                /* set paging (PG) bit */
     ret                            /* this also flushes prefetch-queue */
 
-.align 2
+/*
+ * The interrupt descriptor table has room for 256 idt's
+ */
+.align 4
 .word 0
 idt_descr:
     .word 256*8-1                # idt contains 256 entries
-    .long idt
-.align 2
-.word 0
-gdt_descr:
-    .word 256*8-1                # so does gdt (not that that's any
-    .long gdt                    # magic number, but it works for me :^)
+    .long 0xc0000000+idt
 
-    .align 8
-idt:    .fill 256,8,0            # idt is uninitialized
+.align 4
+idt:
+    .fill 256,8,0                # idt is uninitialized
 
 /*
- * 第二次的全局描述符地址,这个地址是从0地址开始的, 一共16MB的空间
+ * The real GDT is also 256 entries long - no real reason
  */
-gdt:    
-    .quad 0x0000000000000000    /* NULL descriptor */
-    .quad 0x00c09a0000000fff    /* 16Mb */
-    .quad 0x00c0920000000fff    /* 16Mb */
+.align 4
+.word 0
+gdt_descr:
+    .word 256*8-1
+    .long 0xc0000000+gdt
+
+.align 4
+gdt:
+    .quad 0x0000000000000000    /* NULL descriptor */
+    .quad 0xc0c09a0000000fff    /* 16Mb at 0xC0000000 */
+    .quad 0xc0c0920000000fff    /* 16Mb */
     .quad 0x0000000000000000    /* TEMPORARY - don't use */
-    .fill 252,8,0                /* space for LDT's and TSS's etc */
+    .fill 252,8,0                /* space for LDT's and TSS */
 
diff --git a/fs/exec.c b/fs/exec.c
index 0c4aac8..a3f3fc7 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -191,32 +191,27 @@ static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
     return p;
 }
 
+#define TASK_SIZE    (0xC0000000)
+
 static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
 {
     unsigned long code_limit,data_limit,code_base,data_base;
     int i;
-
-    /* code_limit不够一页则占一页
-     *
-     */
-    code_limit = text_size+PAGE_SIZE -1;
-    code_limit &= 0xFFFFF000;
-    data_limit = 0x4000000;
-    /* 获取当前程序的基地址,并设置数据和代码的基地址一样
-     *
-     */
-    code_base = get_base(current->ldt[1]);
-    data_base = code_base;
-
-    /* 基地址和execv执行前一样,但是limit变成了新的程序的大小
-     *
-     */
+    
+    code_limit = TASK_SIZE;
+    data_limit = TASK_SIZE;
+    code_base = data_base = 0;
+    current->start_code = code_base;
+#ifdef K_DEBUG
+    printk("%s-%d code base %p code limit %p\n", __func__, __LINE__, code_base, code_limit);
+#endif
     set_base(current->ldt[1],code_base);
     set_limit(current->ldt[1],code_limit);
     set_base(current->ldt[2],data_base);
     set_limit(current->ldt[2],data_limit);
+
     
-/* make sure fs points to the NEW data segment */
+    /* make sure fs points to the NEW data segment */
     __asm__("pushl $0x17\n\tpop %%fs"::);
 
     /* 指向64MB的最后一个字节
@@ -225,15 +220,21 @@ static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
     data_base += data_limit;
     
     for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {
+        
         /*
          * data_base 64MB的地址第一个页
          */
         data_base -= PAGE_SIZE;
+
         /* 如果page[i]有效,也就是参数有效
          * 则将此物理页映射到data_base地址处
          */
-        if (page[i])
-            put_page(page[i],data_base);
+        if (page[i]) {
+#ifdef K_DEBUG
+            printk("%s-%d put_page %p to %p\n", __func__, __LINE__, page[i], data_base);
+#endif
+            put_page(page[i], data_base);
+        }
     }
     /*
      * 返回64M
@@ -402,7 +403,6 @@ restart_interp:
         goto exec_error2;
     }
     if (N_TXTOFF(ex) != BLOCK_SIZE) {
-        printk("%s: N_TXTOFF != BLOCK_SIZE. See a.out.h.", filename);
         retval = -ENOEXEC;
         goto exec_error2;
     }
@@ -426,8 +426,7 @@ restart_interp:
         if ((current->close_on_exec>>i)&1)
             sys_close(i);
     current->close_on_exec = 0;
-    free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
-    free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
+    clear_page_tables(current);
     if (last_task_used_math == current)
         last_task_used_math = NULL;
     current->used_math = 0;
@@ -441,6 +440,10 @@ restart_interp:
     current->brk = ex.a_bss +
         (current->end_data = ex.a_data +
         (current->end_code = ex.a_text));
+#ifdef K_DEBUG
+    printk("%s-%d end_code is %x, end_data is %x ex.a_entry %x\n", 
+        __func__, __LINE__, current->end_code, current->end_data, ex.a_entry);
+#endif
     current->start_stack = p & 0xfffff000;
     current->euid = e_uid;
     current->egid = e_gid;
diff --git a/include/asm/system.h b/include/asm/system.h
index 9f843fd..c137f4e 100644
--- a/include/asm/system.h
+++ b/include/asm/system.h
@@ -213,7 +213,7 @@ __asm__ ("movw $104,%1\n\t" \
     "movb $0x00,%5\n\t" \
     "movb %%ah,%6\n\t" \
     "rorl $16,%%eax" \
-    ::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
+    ::"a" (addr+0xc0000000), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
      "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
     )
 
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 5a160f3..87c7abc 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -5,6 +5,10 @@
 
 extern unsigned long get_free_page(void);
 extern unsigned long put_page(unsigned long page,unsigned long address);
+extern unsigned long put_dirty_page(unsigned long page,unsigned long address);
 extern void free_page(unsigned long addr);
-
+#ifndef PAGE_SIZE
+#define PAGE_SIZE             4096
+#endif
 #endif
+
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 50ae3bc..90d07d5 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -26,8 +26,10 @@
 #define NULL ((void *) 0)
 #endif
 
-extern int copy_page_tables(unsigned long from, unsigned long to, long size);
-extern int free_page_tables(unsigned long from, unsigned long size);
+extern int copy_page_tables(struct task_struct *tsk);
+extern int free_page_tables(struct task_struct *tsk);
+extern void clear_page_tables(struct task_struct * tsk);
+extern void show_mem(void);
 
 extern void sched_init(void);
 extern void schedule(void);
@@ -125,8 +127,8 @@ struct task_struct {
 /* filp */    {NULL,}, \
     { \
         {0,0}, \
-/* ldt */    {0x9f,0xc0fa00}, \
-        {0x9f,0xc0f200}, \
+/* ldt */        {0xfff,0xc0c0fa00}, \
+        {0xfff,0xc0c0f200} \
     }, \
 /*tss*/    {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
      0,0,0,0,0,0,0,0, \
@@ -181,7 +183,7 @@ __asm__("str %%ax\n\t" \
  * This also clears the TS-flag if the task we switched to has used
  * tha math co-processor latest.
  */
-//#define CONFIG_TASK_TSS 1
+#define CONFIG_TASK_TSS 1
 #ifdef CONFIG_TASK_TSS
 #define switch_to(n) {\
 struct {long a,b;} __tmp; \
diff --git a/init/main.c b/init/main.c
index cd0b564..f30b861 100644
--- a/init/main.c
+++ b/init/main.c
@@ -173,6 +173,7 @@ void main(int __a, int __b, int __c)        /* This really IS void, no error here. */
     printk("kernel fp init\n");
     floppy_init();
     printk("kernel move to user\n");
+    show_mem();
     /*
      * sti允许中断
      *
@@ -262,43 +263,74 @@ static char * envp[] = { "HOME=/usr/root", NULL };
 void init(void)
 {
     int pid,i;
+    int j = 0;
 
     setup((void *) &drive_info);
     (void) open("/dev/tty0",O_RDWR,0);
     (void) dup(0);
     (void) dup(0);
-    printf("init current pid is %d\n", getpid());
     printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
         NR_BUFFERS*BLOCK_SIZE);
     printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);
-
+    
+#if 0
     if (!(pid=fork())) {
-        printf("init fork current pid is %d\n", getpid());
+        printf("%s-%d this is task %d\n", __func__, __LINE__, getpid());
         close(0);
         if (open("/etc/rc",O_RDONLY,0))
             _exit(1);
         execve("/bin/sh",argv_rc,envp_rc);
         _exit(2);
     }
-    if (pid>0)
-        while (pid != wait(&i))
+    printf("%s-%d this is task %d\n", __func__, __LINE__, getpid());
+    if (pid>0) {
+        while (pid != wait(&i));
+    }
+#endif
+#if 0
+    printf("%s-%d this is task %d\n", __func__, __LINE__, getpid());
+
+    pid = fork();
+    if (pid < 0) {
+        printf("fork failed\n");
+        return;
+    }
 
-            /* nothing */;
+    if (!pid) {
+        printf("this is a test pid %d\n", getpid());
+        _exit(2);
+    }
+
+    if (pid > 0) {
+        int j = wait(&i);
+        printf("jjjjjjjjjjjjjjjjjj is %d\n", j);
+        
+    }
+#endif
+    /* nothing */;
     while (1) {
-        printf("start enter init while(1)\n");
         if ((pid=fork())<0) {
-            printf("init while(1) pid is %d\n", getpid());
             printf("Fork failed in init\r\n");
             continue;
         }
         if (!pid) {
-            printf("while1 fork current pid is %d\n", getpid());
+            printf("%s-%d this is task %d\n", __func__, __LINE__, getpid());
             close(0);close(1);close(2);
             setsid();
             (void) open("/dev/tty0",O_RDWR,0);
             (void) dup(0);
             (void) dup(0);
-            _exit(execve("/bin/sh",argv,envp));
+            int t = execve("/bin/sh",argv,envp);
+            printf("dddddddddddddddddddd\n");
+            printf("dddddddddddddddddddd\n");
+            printf("dddddddddddddddddddd\n");
+            printf("dddddddddddddddddddd\n");
+            printf("dddddddddddddddddddd\n");
+            printf("dddddddddddddddddddd\n");
+            printf("dddddddddddddddddddd\n");
+            printf("dddddddddddddddddddd\n");
+            printf("dddddddddddddddddddd\n");
+            _exit(t);
         }
         while (1)
             if (pid == wait(&i))
@@ -306,5 +338,7 @@ void init(void)
         printf("\n\rchild %d died with code %04x\n\r",pid,i);
         sync();
     }
+    printf("DDDDDDDDDDDDDD\n");
     _exit(0);    /* NOTE! _exit, not exit() */
 }
+
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index ed14fa8..6d3a927 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -66,7 +66,7 @@ struct tty_struct tty_table[] = {
         {0, /* no translation */
         0,  /* no translation */
         B2400 | CS8,
-        0,
+        ECHO,
         0,
         INIT_C_CC},
         0,
@@ -79,7 +79,7 @@ struct tty_struct tty_table[] = {
         {0, /* no translation */
         0,  /* no translation */
         B2400 | CS8,
-        0,
+        ECHO,
         0,
         INIT_C_CC},
         0,
diff --git a/kernel/exit.c b/kernel/exit.c
index b22de34..e3b009d 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -102,8 +102,8 @@ static void tell_father(int pid)
 int do_exit(long code)
 {
     int i;
-    free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
-    free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
+
+    free_page_tables(current);
     for (i=0 ; i)
         if (task[i] && task[i]->father == current->pid) {
             task[i]->father = 1;
@@ -128,7 +128,13 @@ int do_exit(long code)
         kill_session();
     current->state = TASK_ZOMBIE;
     current->exit_code = code;
+#ifdef K_DEBUG
+    printk("%s-%d state is %d code is %d  current %d father %d start\n", __func__, __LINE__, current->state, code, current->pid, current->father);
+#endif
     tell_father(current->father);
+#ifdef K_DEBUG
+    printk("%s-%d state is %d code is %d  current %d father %d end\n", __func__, __LINE__, current->state, code, current->pid, current->father);
+#endif
     schedule();
     return (-1);    /* just to suppress warnings */
 }
@@ -142,7 +148,9 @@ int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
 {
     int flag, code;
     struct task_struct ** p;
-
+#ifdef K_DEBUG
+    printk("%s-%d syswaitpid %d\n", __func__, __LINE__, current->pid);
+#endif
     verify_area(stat_addr,4);
 repeat:
     flag=0;
@@ -185,8 +193,9 @@ repeat:
             return 0;
         current->state=TASK_INTERRUPTIBLE;
         schedule();
-        if (!(current->signal &= ~(1<<(SIGCHLD-1))))
+        if (!(current->signal &= ~(1<<(SIGCHLD-1)))) {
             goto repeat;
+        }
         else
             return -EINTR;
     }
diff --git a/kernel/fork.c b/kernel/fork.c
index 25e3207..bf653d7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -42,40 +42,27 @@ 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;
 
-    /*
-     * ?á???μ±?μ???è?·?μ?ú??γ¤???y??γ¤??-     */
-    code_limit=get_limit(0x0f);    
-    data_limit=get_limit(0x17);
-
-    /*
-     * ?á?μ±???3????è?·?μ?ú??γ¤???y??γ¤??-     */
+    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]);
-    /*
-     * Β??μà′ú??κ?y??ε?ùμ?·???μ?-     *
-     */
-    if (old_data_base != old_code_base)
+    if (old_data_base != old_code_base) {
+        printk("ldt[0]: %08x %08x\n",current->ldt[0].a,current->ldt[0].b);
+        printk("ldt[1]: %08x %08x\n",current->ldt[1].a,current->ldt[1].b);
+        printk("ldt[2]: %08x %08x\n",current->ldt[2].a,current->ldt[2].b);
         panic("We don't support separate I&D");
-    /*
-     * ?1????ε?¤????′ú??ε?¤??22?А
-     */
+    }
     if (data_limit < code_limit)
         panic("Bad data_limit");
-    new_data_base = new_code_base = nr * 0x4000000;
+    new_data_base = old_data_base;
+    new_code_base = old_code_base;
     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;
+    return copy_page_tables(p);
 }
 
+
 extern void first_return_from_kernel(void);
 
 /*
@@ -100,6 +87,8 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
         return -EAGAIN;
     task[nr] = p;
 
+    
+
     // NOTE!: the following statement now work with gcc 4.3.2 now, and you
     // must compile _THIS_ memcpy without no -O of gcc.#ifndef GCC4_3
     /* ?1???á?memcpy oˉ?£???task_struct???áao?廡??±′??????@@ -169,6 +158,7 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
     
 #endif
 
+
     if (last_task_used_math == current)
         __asm__("clts ; fnsave %0"::"m" (p->tss.i387));
     if (copy_mem(nr,p)) {
@@ -185,9 +175,13 @@ int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
         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 */
+#ifdef K_DEBUG
+    printk("%s-%d set task %d state to running father %d\n", __func__, __LINE__, p->pid, p->father);
+#endif
     return last_pid;
 }
 
diff --git a/kernel/printk.c b/kernel/printk.c
index fe84b2b..2a60a9b 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -34,7 +34,7 @@ int printk(const char *fmt, ...)
 {
     va_list args;
     int i;
-    int j;
+    int j = 0;
     
     va_start(args, fmt);
     j=timestamp("[%010d] ", jiffies);
diff --git a/kernel/sched.c b/kernel/sched.c
index 68cc50c..c1654c6 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -143,9 +143,29 @@ void schedule(void)
                 (*p)->counter = ((*p)->counter >> 1) +
                         (*p)->priority;
     }
+    
 #ifndef CONFIG_TASK_TSS
     switch_to_by_stack((long)pnext, (long)(_LDT(next)));
 #else
+#if 0
+    printk("%s switch to %d\n", __func__, next);
+    if (next == 1) {
+        unsigned long dir = task[next]->tss.cr3;
+        unsigned long *page_dir;
+        unsigned long page_table;
+        printk("task1 cr3 is %p\n", dir);
+        page_dir = (unsigned long *) dir;
+        for (i = 0 ; i < 1024 ; i++,page_dir++) {
+            page_table = *page_dir;
+            if (!page_table)
+                continue;
+            if (!(1 & page_table)) {
+                continue;
+            }
+            printk("xxxxxxxxxxx page_table reserve %p\n", page_table);
+        }
+    }
+#endif
     switch_to(next);
 #endif
 }
diff --git a/kernel/traps.c b/kernel/traps.c
index ce10949..25830d9 100644
--- a/kernel/traps.c
+++ b/kernel/traps.c
@@ -36,6 +36,22 @@ register unsigned short __res; \
 __asm__("mov %%fs,%%ax":"=a" (__res):); \
 __res;})
 
+#define _ss() ({ \
+    register unsigned short __res; \
+    __asm__("mov %%ss,%%ax":"=a" (__res):); \
+    __res;})
+    
+#define _cs() ({ \
+    register unsigned short __res; \
+    __asm__("mov %%cs,%%ax":"=a" (__res):); \
+    __res;})
+    
+#define _ds() ({ \
+        register unsigned short __res; \
+        __asm__("mov %%ds,%%ax":"=a" (__res):); \
+        __res;})
+
+
 int do_exit(long code);
 
 void page_exception(void);
@@ -65,11 +81,16 @@ static void die(char * str,long esp_ptr,long nr)
     long * esp = (long *) esp_ptr;
     int i;
 
+    printk("esp is %p %p %p %p %p %p\n", esp, esp[0], esp[1], esp[2], esp[3], esp[4]);
     printk("%s: %04x\n\r",str,nr&0xffff);
     printk("EIP:\t%04x:%p\nEFLAGS:\t%p\nESP:\t%04x:%p\n",
         esp[1],esp[0],esp[2],esp[4],esp[3]);
     printk("fs: %04x\n",_fs());
-    printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x17));
+    printk("ss: %04x\n",_ss());
+    printk("cs: %04x\n",_cs());
+    printk("ds: %04x\n",_ds());
+    printk("base: %p, limit: %p\n",get_base(current->ldt[1]),get_limit(0x0f));
+    printk("data: %p, limit: %p\n",get_base(current->ldt[2]),get_limit(0x17));
     if (esp[4] == 0x17) {
         printk("Stack: ");
         for (i=0;i<4;i++)
diff --git a/mm/memory.c b/mm/memory.c
index c6c6ccb..e451c32 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -35,17 +35,22 @@ static inline void oom(void)
 }
 
 #define invalidate() \
-__asm__("movl %%eax,%%cr3"::"a" (0))
+__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3":::"ax")
+
 
 /* these are not to be changed without changing head.s etc */
-#define LOW_MEM             0x100000
-#define PAGING_MEMORY         (15*1024*1024)
+
+#define PAGING_MEMORY         (16*1024*1024)
 #define PAGING_PAGES         (PAGING_MEMORY>>12)
-#define MAP_NR(addr)         (((addr)-LOW_MEM)>>12)
-#define USED                 100
+#define MAP_NR(addr)         (((unsigned long)(addr))>>12)
+#define USED                 (1<<7)
+#define PAGE_DIRTY            0x40
+#define PAGE_ACCESSED        0x20
+#define PAGE_USER            0x04
+#define PAGE_RW                0x02
+#define PAGE_PRESENT        0x01
+#define PAGE_SHIFT             12
 
-#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \
-current->start_code + current->end_code)
 
 static long HIGH_MEMORY = 0;
 static long total_pages = 0;
@@ -84,7 +89,7 @@ __asm__("std ; repne ; scasb\n\t"
     " movl %%edx,%%eax\n"
     "1: cld"
     :"=a" (__res)
-    :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
+    :"0" (0),"i" (0),"c" (PAGING_PAGES),
     "D" (mem_map+PAGING_PAGES-1)
     );
 return __res;
@@ -99,335 +104,238 @@ return __res;
  */
 void free_page(unsigned long addr)
 {
-    if (addr < LOW_MEM) {
-        return;
-    }
+    int i = 0;
+    
     if (addr >= HIGH_MEMORY) {
         panic("trying to free nonexistent page");
     }
-    /* 
-     * 物理内存减去低端内存然后除以4KB得到物理页号,
-     * 获取页时mem_map[addr]设置为1,因此释放时mem_map[addr]--为0,从而释放页
-     * 这里多了一个判断是因为此页可能被共享,如果是共享的页只是减少计数
-     * 当计数为0才真正的释放页
-     *
-     */
-    addr -= LOW_MEM;
-    addr >>= 12;
-    if (mem_map[addr]--) {
+
+    i = MAP_NR(addr);
+
+    if (mem_map[i] & USED) {
+        printk("system reserve mem, ignore free\n");
         return;
     }
-    mem_map[addr] = 0;
-    panic("trying to free free page");
+
+    if (!mem_map[i]) {
+        panic("trying to free free page");
+    }
+
+    mem_map[i]--;
+    return;
 }
 
-/*
- * This function frees a continuos block of page tables, as needed
- * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.
- *
- * 释放页表连续的内存块
- * 根据线性地址和长度,释放对应内存页表所制定的内存块并设置表项空闲
- * 该函数处理4MB的内存块
- *
- */
-int free_page_tables(unsigned long from,unsigned long size)
+static void free_one_table(unsigned long * page_dir)
 {
-    unsigned long *pg_table;
-    unsigned long * dir, nr;
 
-    /*
-     * 释放的内存块地址需要以4MB为边界
-     *
-     */
-    if (from & 0x3fffff) {
-        panic("free_page_tables called with wrong alignment");
-    }
-    /*
-     * 0地址为内核和内核缓冲区,不能释放
-     *
-     */
-    if (!from) {
-        panic("Trying to free up swapper memory space");
+    int j;
+    unsigned long pg_table = *page_dir;
+    unsigned long * page_table;
+
+    if (!pg_table)
+        return;
+        
+    if (pg_table >= HIGH_MEMORY|| !(pg_table & 1)) {
+        printk("Bad page table: [%08x]=%08x\n",page_dir,pg_table);
+        *page_dir = 0;
+        return;
     }
     
-    /* 
-     * 计算所占页表目录项数,
-     * 一个页面目录项大小为4MB, 一共1024个页表目录项,共4GB空间
-     *
-     * size + 0x3fffff表示将size扩大到4MB然后对齐
-     * 经过这样的计算size表示的是需要释放的页表目录数量
-     *
-     */
-    size = (size + 0x3fffff) >> 22;
-    
-    /* 
-     * 计算from所在的页面目录项,
-     * 目录项索引为form >> 22, 
-     * 由于每项占用4个字节,并且页目录是从0地址开始,
-     * 因此实际的目录项地址为(from >> 22) << 2即from >> 20
-     *
-     */
-    dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
-
-    /* 
-     * 主循环是页表目录项
-     * size表示有多少个页表目录项
-     * dir表示页表目录项的地址地址,每加一次就是下一个页表目录项
-     *
-     */
-    for ( ; size-- > 0; dir++) {
-        /*
-         * 如果该页表目录无效继续,页表目录的低12位有特殊的意义,在计算
-         * 页表时低12位可全部看作0,因为页表目录,页表,页都要求4KB对齐
-         *
-         */
-        if (!(1 & *dir)) {
+    *page_dir = 0;
+    if (mem_map[MAP_NR(pg_table)] & USED) {
+        return;
+    }
+        
+    page_table = (unsigned long *) (pg_table & 0xfffff000);
+    for (j = 0 ; j < 1024 ; j++,page_table++) {
+        unsigned long pg = *page_table;
+        
+        if (!pg)
             continue;
-        }
-        /* 
-         * 取页表的物理地址
-         *
-         */
-        pg_table = (unsigned long *) (0xfffff000 & *dir);
-
-        /* 
-         * 每一个页表有1024个页,此处是循环释放1024个页
-         *
-         */
-        for (nr=0; nr<1024; nr++) {
-            /*
-             * 如果此页有效,则释放此页
-             * 0xfffff000 & *pg_table 表示页的物理地址
-             *
-             *
-             */
-            if (1 & *pg_table) {
-                free_page(0xfffff000 & *pg_table);
-            }
-            /* 
-             * 此页表项清零,指向下一个页表项
-             *
-             */
-            *pg_table = 0;
-            pg_table++;
-        }
-        /* 由于一个页表也占用了一个页,
-         * 当页表里面的页释放完成后,释放此页表
-         * 0xfffff000 & *dir 表示页表的物理地址
-         *
-         *
-         */
-        free_page(0xfffff000 & *dir);
-        *dir = 0;
+        *page_table = 0;
+        if (1 & pg)
+            free_page(0xfffff000 & pg);
+    }
+    free_page(0xfffff000 & pg_table);
+}
+
+void clear_page_tables(struct task_struct * tsk)
+{
+    int i;
+    unsigned long * page_dir;
+    unsigned long tmp;
+
+    if (!tsk)
+        return;
+    if (tsk == task[0])
+        panic("task[0] (swapper) doesn't support exec() yet\n");
+
+
+    page_dir = (unsigned long *) tsk->tss.cr3;
+    if (!page_dir) {
+        printk("Trying to clear kernel page-directory: not good\n");
+        return;
     }
+    for (i = 0 ; i < 768 ; i++,page_dir++)
+        free_one_table(page_dir);
+    
+    //tmp = (unsigned long)(page_dir + 768);
     invalidate();
-    return 0;
+    return;
 }
 
+
 /*
- *  Well, here is one of the most complicated functions in mm. It
- * copies a range of linerar addresses by copying only the pages.
- * Let's hope this is bug-free, 'cause this one I don't want to debug :-)
- *
- * Note! We don't copy just any chunks of memory - addresses have to
- * be divisible by 4Mb (one page-directory entry), as this makes the
- * function easier. It's used only by fork anyway.
- *
- * NOTE 2!! When from==0 we are copying kernel space for the first
- * fork(). Then we DONT want to copy a full page-directory entry, as
- * that would lead to some serious memory waste - we just copy the
- * first 160 pages - 640kB. Even that is more than we need, but it
- * doesn't take any more memory - we don't copy-on-write in the low
- * 1 Mb-range, so the pages can be shared with the kernel. Thus the
- * special case for nr=xxxx.
+ * This function frees up all page tables of a process when it exits.
  */
-int copy_page_tables(unsigned long from, unsigned long to, long size)
+int free_page_tables(struct task_struct * tsk)
 {
-    unsigned long * from_page_table;
-    unsigned long * to_page_table;
-    unsigned long this_page;
-    unsigned long * from_dir, * to_dir;
-    unsigned long nr;
+    int i;
+    unsigned long pg_dir;
+    unsigned long * page_dir;
 
-    /*
-     * 源地址和目的地址都是要在4M的边界上
-     *
-     */
-    if ((from&0x3fffff) || (to&0x3fffff)) {
-        panic("copy_page_tables called with wrong alignment");
+    if (!tsk)
+        return 1;
+    if (tsk == task[0]) {
+        printk("task[0] (swapper) killed: unable to recover\n");
+        panic("Trying to free up swapper memory space");
     }
+    pg_dir = tsk->tss.cr3;
+    if (!pg_dir) {
+        printk("Trying to free kernel page-directory: not good\n");
+        return 1;
+    }
+    tsk->tss.cr3 = (unsigned long) 0;
+    if (tsk == current)
+        __asm__ __volatile__("movl %0,%%cr3"::"a" (tsk->tss.cr3));
+    page_dir = (unsigned long *) pg_dir;
+    for (i = 0 ; i < 1024 ; i++,page_dir++)
+        free_one_table(page_dir);
+    free_page(pg_dir);
+    invalidate();
+    return 0;
+}
 
-    /* 
-     * 获取源页表目录项和目的页表目录项的地址指针,以及大小size
-     * 如果看不懂,请看free_page_tables函数的说明
-     *
-     *
-     */
-    from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
-    to_dir = (unsigned long *) ((to>>20) & 0xffc);
-    size = ((unsigned) (size+0x3fffff)) >> 22;
-
-    for( ; size-->0 ; from_dir++,to_dir++) {
-        /*
-         * 如果目的目录项的页表已经存在,则出错
-         *
-         */
-        if (1 & *to_dir) {
-            panic("copy_page_tables: already exist");
-        }
-        /*
-         * 如果源目录项的页表不存在,则忽略
-         */
-        if (!(1 & *from_dir)) {
+
+/*
+ * copy_page_tables() just copies the whole process memory range:
+ * note the special handling of RESERVED (ie kernel) pages, which
+ * means that they are always shared by all processes.
+ */
+int copy_page_tables(struct task_struct * tsk)
+{
+    int i;
+    int c = 0;
+    unsigned long old_pg_dir, *old_page_dir;
+    unsigned long new_pg_dir, *new_page_dir;
+
+    old_pg_dir = current->tss.cr3;
+    new_pg_dir = get_free_page();
+    if (!new_pg_dir)
+        return -1;
+    c++;
+#ifdef K_DEBUG
+    printk("old_page_dir %p nr %d old pid %d\n", old_pg_dir, mem_map[MAP_NR(old_pg_dir)], current->pid);
+    printk("new_page_dir %p nr %d new pid %d\n", new_pg_dir, mem_map[MAP_NR(new_pg_dir)], tsk->pid);
+#endif    
+    tsk->tss.cr3 = new_pg_dir;
+    old_page_dir = (unsigned long *) old_pg_dir;
+    new_page_dir = (unsigned long *) new_pg_dir;
+    for (i = 0 ; i < 1024 ; i++,old_page_dir++,new_page_dir++) {
+        int j;
+        unsigned long old_pg_table, *old_page_table;
+        unsigned long new_pg_table, *new_page_table;
+
+        old_pg_table = *old_page_dir;
+        if (!old_pg_table)
+            continue;
+        if (old_pg_table >= HIGH_MEMORY || !(1 & old_pg_table)) {
+            printk("copy_page_tables: bad page table: "
+                "probable memory corruption  %d %p\n", i, old_pg_table);
+            *old_page_dir = 0;
             continue;
         }
-
-        /*
-         * 获取源页表地址
-         */
-        from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
-        /*
-         * 获取一个空闲页面作为目的页表
-         */
-        if (!(to_page_table = (unsigned long *) get_free_page())) {
-            return -1;    /* Out of memory, see freeing */
+        if (mem_map[MAP_NR(old_pg_table)] & USED) {
+#ifdef K_DEBUG
+            printk("%s-%d i %d new_page_dir is %p old_pg_table is %p kernel reserve\n", __func__, __LINE__, i, new_page_dir, old_pg_table);
+#endif
+            *new_page_dir = old_pg_table;
+            continue;
         }
-
-        /* 设置目的页表目录的地址为新申请的物理页表地址并设置属性
-         * 设置页表,并将此也变的后3位设置为111,表示(usr, RW, preset)
-         *
-         */
-        *to_dir = ((unsigned long) to_page_table) | 7;
-
-        /* from == 0表示是内核空间的页表目录项的起始地址
-         * 如果是内核则只需拷贝160个页,640KB的空间
-         * 640KB也是定义INIT_TASK的数据段和代码段长度
-         * 如果是其他也就是非任务0,则拷贝1024个页,共4MB空间
-         *
-         */
-        //nr = (from == 0) ? 0xA0 :1 024;
-        if (from) {
-            nr = 1024;
-        } else {
-            nr = 160;
+#ifdef K_DEBUG
+        printk("%s-%d i %d new_page_dir is %p old_pg_table is %p\n", __func__, __LINE__, i, new_page_dir, old_pg_table);
+#endif
+        new_pg_table = get_free_page();
+        if (!new_pg_table) {
+            free_page_tables(tsk);
+            return -1;
         }
-        
-        for ( ; nr-- > 0; from_page_table++, to_page_table++) {
-            /*
-             * 将当前源页表项存到临时变量this_page
-             *
-             */
-            this_page = *from_page_table;
-            /* 
-             * 如果当前的页表项不存在则不用拷贝
-             */
-            if (!(1 & this_page)) {
+        c++;
+        *new_page_dir = new_pg_table | PAGE_ACCESSED | 7;
+        old_page_table = (unsigned long *) (0xfffff000 & old_pg_table);
+        new_page_table = (unsigned long *) (0xfffff000 & new_pg_table);
+        for (j = 0 ; j < 1024 ; j++,old_page_table++,new_page_table++) {
+            unsigned long pg;
+            pg = *old_page_table;
+            if (!pg)
+                continue;
+            if (!(pg & PAGE_PRESENT)) {
                 continue;
             }
-            /*
-             * 设置目的页表为只读,我们看到目的页表为只读
-             *
-             */
-            this_page &= ~2;
-            /*
-             * 将临时页表项内容赋值给目的页表项
-             * 通过此代码我们看到,
-             * 系统只是做了页表的设置并没有实现真正的数据拷贝
-             *
-             */
-            *to_page_table = this_page;
-            /* 
-             * 对于是1MB以下的内存,说明是内核页面因此不需要对mem_map进行设置
-             * 
-             * 如果代码是在任务0中创建任务1,则下面的代码不会用到
-             * 只有当调用者的代码处于主内存中(大于LOW_MEN)1MB时才会执行
-             * 这种情况需要在进程调用了execve()装载并执行了新代码才会出现
-             *
-             *
-             */
-            if (this_page > LOW_MEM) {
-                /* 
-                 * 下面的内容是使其源页表项也可读,这样哪个进程先写会触发
-                 * 缺页异常从而分配页进行使用
-                 *
-                 *
-                 */
-                *from_page_table = this_page;
-                this_page -= LOW_MEM;
-                this_page >>= 12;
-                mem_map[this_page]++;
-            }
+            pg &= ~2;
+            *new_page_table = pg;
+            if (mem_map[MAP_NR(pg)] & USED)
+                continue;
+            *old_page_table = pg;
+            mem_map[MAP_NR(pg)]++;
         }
     }
     invalidate();
+#ifdef K_DEBUG
+    printk("%s-%d get free pages number %d\n", __func__, __LINE__, c);
+#endif
     return 0;
 }
 
-/*
- * This function puts a page in memory at the wanted address.
- * It returns the physical address of the page gotten, 0 if
- * out of memory (either when trying to access page-table or
- * page.)
- *
- * 下面的代码将一个物理页放在制定的address处,返回物理地址
- */
-unsigned long put_page(unsigned long page,unsigned long address)
+unsigned long put_page(unsigned long page, unsigned long address)
 {
     unsigned long tmp, *page_table;
+    struct task_struct *tsk = current;
 
-    /* NOTE !!! This uses the fact that _pg_dir=0 */
+/* NOTE !!! This uses the fact that _pg_dir=0 */
 
-    /* chenwg
-     * 如果页小于1M或者大于HIGH_MEMORY则告警
-     * 如果所在的页的映射没有置位则告警
-     *
-     */
-    if (page < LOW_MEM || page >= HIGH_MEMORY) {
-        printk("Trying to put page %p at %p\n",page,address);
-    }
-    if (mem_map[(page-LOW_MEM)>>12] != 1) {
+    if (page >= HIGH_MEMORY)
+        printk("put_dirty_page: trying to put page %p at %p\n",page,address);
+        
+    if (mem_map[MAP_NR(page)] != 1)
         printk("mem_map disagrees with %p at %p\n",page,address);
-    }
+        
+    page_table = (unsigned long *) (tsk->tss.cr3 + ((address>>20) & 0xffc));
+#ifdef K_DEBUG
+    printk("%s-%d page_table is %p page is %p address %p pid is %d\n", __func__, __LINE__, page_table, page, address, current->pid);
+#endif
     
-    /* chenwg
-     * 根据地址计算页表目录项指针,在内核态中,页表目录从0地址开始,我们知道
-     * 在启用了CPU的页式内存管理后,虚拟地址右移22位得到页表目录的索引号
-     * 又因为每个页表目录占用4个字节因此将索引左移2位得到页表目录的地址,
-     * 页表目录的地址存放是页表的地址,每个页表要求4KB对其,每个页也要求4KB对齐
-     * 因此不管是页表目录存放的页表的地址还是页表里存放页的地址都低12位无效
-     * 所有的计算都已页表在0地址存放为基础
-     *
-     */
-    page_table = (unsigned long *) ((address>>20) & 0xffc);
-
-    /* chenwg
-     * *page_table获取页表的地址,其bit0表示该页表是否有效
-     * 如果有效获取页表地址
-     * 否则获取一个页作为页表
-     *
-     */
-    if ((*page_table)&1) {
+    if ((*page_table)&1)
         page_table = (unsigned long *) (0xfffff000 & *page_table);
-    } else {
-        if (!(tmp=get_free_page())) {
+    else {
+        if (!(tmp=get_free_page()))
             return 0;
-        }
-        *page_table = tmp|7;
+        *page_table = tmp | PAGE_ACCESSED |7;
         page_table = (unsigned long *) tmp;
     }
-    /* chenwg
-     * address>>12表示这个虚拟地址在页表中的偏移
-     * 在页表的制定位置写上物理地址并设置此页有效
-     *
-     */
-    page_table[(address>>12) & 0x3ff] = page | 7;
-    /*
-     * 页表发生变化了,不明白为什么不用刷新
-     */
-    /* no need for invalidate */
+    page_table += (address >> PAGE_SHIFT) & 0x3ff;
+    if (*page_table) {
+        printk("put_dirty_page: page already exists\n");
+        *page_table = 0;
+        invalidate();
+    }
+    *page_table = page | (PAGE_DIRTY | PAGE_ACCESSED | 7);
+/* no need for invalidate */
     return page;
 }
 
+
+
 /*
  * table_entry页表项指针
  */
@@ -436,19 +344,26 @@ void un_wp_page(unsigned long * table_entry)
     unsigned long old_page,new_page;
 
     
-    /* 获取此页对应的物理地址
+    /* 获取此页对应的物理地址,如果原页面不是保留并且其值为1表示没有共享,设置写标记
      *
      */
     old_page = 0xfffff000 & *table_entry;
-    if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
+
+    if (!(mem_map[MAP_NR(old_page)] & USED) && mem_map[MAP_NR(old_page)]==1) {
         *table_entry |= 2;
         invalidate();
         return;
     }
     if (!(new_page=get_free_page()))
         oom();
-    if (old_page >= LOW_MEM)
+
+    /*
+     *  如果原页面不是保留且不为1,表示已经被共享,给其值减一,设置新的页表
+     *
+     */
+    if (!(mem_map[MAP_NR(old_page)] & USED))
         mem_map[MAP_NR(old_page)]--;
+    
     *table_entry = new_page | 7;
     invalidate();
     copy_page(old_page,new_page);
@@ -468,18 +383,47 @@ void do_wp_page(unsigned long error_code,unsigned long address)
 /* stupid, stupid. I really want the libc.a from GNU */
     if (CODE_SPACE(address))
         do_exit(SIGSEGV);
+        un_wp_page((unsigned long *)address);
+    (((address>>10) & 0xffc) + (0xfffff000 &
+    *((unsigned long *) ((address>>20) &0xffc)))));
 #endif
+
+    unsigned long* dir_base = (unsigned long *)current->tss.cr3;
+    unsigned long* dir_item = dir_base + (address >> 22);
     un_wp_page((unsigned long *)
-        (((address>>10) & 0xffc) + (0xfffff000 &
-        *((unsigned long *) ((address>>20) &0xffc)))));
+        (((address>>10) & 0xffc) + (0xfffff000 & *dir_item)));
 
+#if 0
+    unsigned long address;
+
+    printk("%s address is %p start is %p pid %d\n", __func__, __address, current->start_code, current->pid);
+    /*
+     * 页表地址
+     */
+    address = current->tss.cr3 + ((__address>>20) & 0xffc);
+    /*
+     * 页表地址
+     */
+    address = address & 0xfffff000;
+    /*
+     * 页在页表的地址
+     */
+    address = address + (__address>>10) & 0xffc;
+    /*
+     * 页的物理地址
+     */
+    address = *(unsigned long *)(address);
+    un_wp_page((unsigned long *)address);
+#endif
 }
 
+
 void write_verify(unsigned long address)
 {
     unsigned long page;
 
-    if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1))
+    page = *(unsigned long *) (current->tss.cr3 + ((address>>20) & 0xffc));
+    if (!(page & PAGE_PRESENT))
         return;
     page &= 0xfffff000;
     page += ((address>>10) & 0xffc);
@@ -508,34 +452,37 @@ void get_empty_page(unsigned long address)
  */
 static int try_to_share(unsigned long address, struct task_struct * p)
 {
+    struct task_struct *tsk = current;
+    
     unsigned long from;
     unsigned long to;
     unsigned long from_page;
     unsigned long to_page;
     unsigned long phys_addr;
 
-    from_page = to_page = ((address>>20) & 0xffc);
-    from_page += ((p->start_code>>20) & 0xffc);
-    to_page += ((current->start_code>>20) & 0xffc);
-/* is there a page-directory at from? */
+    from_page = p->tss.cr3 + ((address>>20) & 0xffc);
+    to_page = tsk->tss.cr3 + ((address>>20) & 0xffc);
+    /* is there a page-directory at from? */
     from = *(unsigned long *) from_page;
     if (!(from & 1))
         return 0;
     from &= 0xfffff000;
     from_page = from + ((address>>10) & 0xffc);
     phys_addr = *(unsigned long *) from_page;
-/* is the page clean and present? */
+    /* is the page clean and present? */
     if ((phys_addr & 0x41) != 0x01)
         return 0;
     phys_addr &= 0xfffff000;
-    if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM)
+    if (phys_addr >= HIGH_MEMORY)
+        return 0;
+    if (mem_map[MAP_NR(phys_addr)] & USED)
         return 0;
     to = *(unsigned long *) to_page;
     if (!(to & 1)) {
-        if ((to = get_free_page()))
-            *(unsigned long *) to_page = to | 7;
-        else
-            oom();
+        to = get_free_page();
+        if (!to)
+            return 0;
+        *(unsigned long *) to_page = to | PAGE_ACCESSED | 7;
     }
     to &= 0xfffff000;
     to_page = to + ((address>>10) & 0xffc);
@@ -545,10 +492,10 @@ static int try_to_share(unsigned long address, struct task_struct * p)
     *(unsigned long *) from_page &= ~2;
     *(unsigned long *) to_page = *(unsigned long *) from_page;
     invalidate();
-    phys_addr -= LOW_MEM;
-    phys_addr >>= 12;
+    phys_addr >>= PAGE_SHIFT;
     mem_map[phys_addr]++;
     return 1;
+
 }
 
 /*
@@ -567,6 +514,7 @@ static int share_page(unsigned long address)
         return 0;
     if (current->executable->i_count < 2)
         return 0;
+        
     for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
         if (!*p)
             continue;
@@ -587,8 +535,31 @@ void do_no_page(unsigned long error_code,unsigned long address)
     unsigned long page;
     int block,i;
 
+    
     address &= 0xfffff000;
     tmp = address - current->start_code;
+
+#ifdef K_DEBUG
+    printk("%s address is %p start is %p pid %d\n", __func__, address, current->start_code, current->pid);
+    if (current->pid == 1) {
+        unsigned long dir = current->tss.cr3;
+        unsigned long *page_dir;
+        unsigned long page_table;
+
+        page_table = (dir + ((address>>20) & 0xffc));
+        page_dir = (unsigned long *) dir;
+        for (i = 0 ; i < 1024 ; i++,page_dir++) {
+            page_table = *page_dir;
+            if (!page_table)
+                continue;
+            if (!(1 & page_table)) {
+                continue;
+            }
+            printk("%s xxxxxxxxxxx page_table reserve %p\n", __func__, page_table);
+            printk("%s xxxxxxxxxxx page reserve %p\n", __func__, (*(unsigned long*)(page_table&0xfffff000)));
+        }
+    }
+#endif
     if (!current->executable || tmp >= current->end_data) {
         get_empty_page(address);
         return;
@@ -597,7 +568,8 @@ void do_no_page(unsigned long error_code,unsigned long address)
         return;
     if (!(page = get_free_page()))
         oom();
-/* remember that 1 block is used for header */
+        
+    /* remember that 1 block is used for header */
     block = 1 + tmp/BLOCK_SIZE;
     for (i=0 ; i<4 ; block++,i++)
         nr[i] = bmap(current->executable,block);
@@ -609,11 +581,12 @@ void do_no_page(unsigned long error_code,unsigned long address)
         *(char *)tmp = 0;
     }
     if (put_page(page,address))
-        return;
+        return;    
     free_page(page);
     oom();
 }
 
+
 long get_total_pages(void)
 {
     return total_pages;
@@ -659,21 +632,26 @@ void mem_init(long start_mem, long end_mem)
         mem_map[i++]=0;
 }
 
-void calc_mem(void)
+void show_mem(void)
 {
-    int i,j,k,free=0;
-    long * pg_tbl;
-
-    for(i=0 ; i)
-        if (!mem_map[i]) free++;
-    printk("%d pages free (of %d)\n\r", free, PAGING_PAGES);
-    for(i=2 ; i<1024 ; i++) {
-        if (1&pg_dir[i]) {
-            pg_tbl=(long *) (0xfffff000 & pg_dir[i]);
-            for(j=k=0 ; j<1024 ; j++)
-                if (pg_tbl[j]&1)
-                    k++;
-            printk("Pg-dir[%d] uses %d pages\n",i,k);
-        }
+    int i,free = 0,total = 0,reserved = 0;
+    int shared = 0;
+
+    printk("Mem-info:\n");
+    
+    i = HIGH_MEMORY >> PAGE_SHIFT;
+    while (i-- > 0) {
+        total++;
+        if (mem_map[i] & USED)
+            reserved++;
+        else if (!mem_map[i])
+            free++;
+        else
+            shared += mem_map[i]-1;
     }
+    printk("Buffer blocks:   %6dMB\n", (nr_buffers*BLOCK_SIZE)/(1024*1024));
+    printk("Tatal pages:     %6dMB\n", (total*PAGE_SIZE)/(1024*1024));
+    printk("Free pages:      %6dMB\n", (free*PAGE_SIZE)/(1024*1024));
+    printk("Reserved pages:  %6dMB\n", (reserved*PAGE_SIZE)/(1024*1024));
+    printk("Shared pages:    %6dMB\n", (shared*PAGE_SIZE)/(1024*1024));
 }