diff --git a/linux/include/linux/mm.h b/linux/include/linux/mm.h index 5a160f3..3939f62 100644 --- a/linux/include/linux/mm.h +++ b/linux/include/linux/mm.h @@ -1,10 +1,22 @@ -#ifndef _MM_H -#define _MM_H -#define PAGE_SIZE 4096 +#ifndef _mm_H +#define _mm_H -extern unsigned long get_free_page(void); + +extern void calc_mem(void); +extern void mem_init(long start_mem, long end_mem); +extern void do_no_page(unsigned long error_code,unsigned long address); +extern int share_page(unsigned long address); +extern int try_to_share(unsigned long address, struct task_struct * p); +extern void get_empty_page(unsigned long address); +extern void write_verify(unsigned long address); +extern void do_wp_page(unsigned long error_code,unsigned long address); +extern void un_wp_page(unsigned long * table_entry); extern unsigned long put_page(unsigned long page,unsigned long address); +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 void free_page(unsigned long addr); - -#endif +extern unsigned long get_free_page(void); +extern void oom(void); +extern void do_exit(long code); +#endif // MACRO diff --git a/linux/kernel/fork.c b/linux/kernel/fork.c index effc165..e17eb40 100644 --- a/linux/kernel/fork.c +++ b/linux/kernel/fork.c @@ -36,7 +36,7 @@ void verify_area(void * addr,int size) } } -int copy_mem(int nr,struct task_struct * p,int flag) +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; @@ -53,7 +53,7 @@ int copy_mem(int nr,struct task_struct * p,int flag) 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)) { + if (copy_page_tables(old_data_base,new_data_base,data_limit)) { free_page_tables(new_data_base,data_limit); return -ENOMEM; } @@ -65,11 +65,12 @@ int copy_mem(int nr,struct task_struct * p,int flag) * 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, +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) { + sys_signal(SIGCHLD,NULL,NULL); struct task_struct *p; int i; struct file *f; @@ -113,7 +114,7 @@ int copy_process(int flag,int nr,long ebp,long edi,long esi,long gs,long none, 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)) { + if (copy_mem(nr,p)) { task[nr] = NULL; free_page((long) p); return -EAGAIN; @@ -147,95 +148,99 @@ int find_empty_process(void) 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) + +int copy_mem_clone(int nr,struct task_struct * p) { - //设置压栈表,方便操作; - 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++); + 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_clone(old_data_base,new_data_base,data_limit)) { + free_page_tables(new_data_base,data_limit); + return -ENOMEM; + } 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)//参数列表不为空,将参数压入栈中,这里直接修改物理页 - { + + + +int copy_process_clone(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 = ebx; + p->tss.eflags = eflags; + p->tss.eax = 0; + p->tss.ecx = ecx; + p->tss.edx = edx; + p->tss.ebx = ebx; + p->tss.esp = ecx; + 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_clone(nr,p)) { + task[nr] = NULL; + free_page((long) p); + return -EAGAIN; } - //char * tmp1=nrfrom, *tmp2=child_stack-1024,len=; - //while() - return 0; + for (i=0; ifilp[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; } -*/ \ No newline at end of file diff --git a/linux/kernel/sys.c b/linux/kernel/sys.c index 8b4d8d1..872ce19 100644 --- a/linux/kernel/sys.c +++ b/linux/kernel/sys.c @@ -179,11 +179,7 @@ unsigned int sys_sleep(unsigned int seconds) return 0; } -int sys_clone() -{ - return -1; -} int sys_ftime() { @@ -463,183 +459,4 @@ int sys_umask(int mask) return (old); } -static int my_share(unsigned long address, struct task_struct * p) -{ - 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 += ((current->start_code>>20) & 0xffc); - to_page += ((p->start_code>>20) & 0xffc); - - from = *(unsigned long *) from_page; - from &= 0xfffff000; - from_page = from + ((address>>10) & 0xffc); - phys_addr = *(unsigned long *) from_page; - to = *(unsigned long *) to_page; - if (!(to & 1)) - if (to = get_free_page()) - *(unsigned long *) to_page = to | 7; - else - return 0; - to &= 0xfffff000; - to_page = to + ((address>>10) & 0xffc); - if (1 & *(unsigned long *) to_page) - return 0; - /* share them: write-protect */ - *(unsigned long *) to_page = *(unsigned long *) from_page; - phys_addr -= LOW_MEM; - phys_addr >>= 12; - mem_map[phys_addr]++; - return 1; -} - -// rememeber to sync when munmap exit manual - -long sys_mmap(void * start,size_t len,...)// int prot,int flags,int fd,off_t off -{ - printk("start mmaping\n"); - /* va_list args; - va_start(args,len); */ - int prot=3,flags=1,fd=3,off=0; - /* prot=va_arg(args,int);flags=va_arg(args,int);fd=va_arg(args,int); - off_t off=va_arg(args,off_t); - int *ll=&len;printk("%d,%d,%d,%d,%d\n",*ll,*(ll+1),*(ll+2),*(ll+3),*(ll+4)); - va_end(args); - printk("%d,%d,%d,%ld\n",prot,flags,fd,off); */ - - int block; - size_t l=len; - struct buffer_head * bh; - char *temp,*p1,*p2; - void * buf=start; - int tempprot=0; - - //因为new.h和namei.c定义不一样,要修改 - if(prot &PROT_READ) tempprot |=4; - if(prot &PROT_EXEC) tempprot |=1; - if(prot &PROT_WRITE) tempprot |=2; - - //特殊量len>0 off%4096==0 prot至少有read权限 - if(len<=0 || off<0 || (off%PAGE_SIZE)) - { - if(len<=0) - printk("the len of the wanting bytes must be positive"); - else - printk("offset must be the mul of 4096"); - return MAP_FAILED; - } - if(!(prot& PROT_READ)) return MAP_FAILED; - - //permissions of the file ,搬运函数namei.c::permissions - printk("fd: %d\n",fd); - struct m_inode *inode=current->filp[fd]->f_inode; - printk("end of permissions\n"); - int mode = inode->i_mode; - if (inode->i_dev && !inode->i_nlinks) - {printk("end of permissions1\n");return MAP_FAILED;} - else if (current->euid==inode->i_uid) - mode >>= 6; - else if (current->egid==inode->i_gid) - mode >>= 3; - if (!(((mode & tempprot & 0007) == tempprot) || suser())) - { - printk("error permission."); - return MAP_FAILED; - } - //end of permission check - printk("end of permissions\n"); - - //设置用户空间的虚拟地址,初始为32MB处,这样写在brk增长至32MB时会有bug,我们忽略 - //同时,当栈向下增长到一定程度时,也会和当前地址冲突,我们忽略 - if(start<=current->brk || start>=current->start_stack-0x8000 || start==NULL) - { - if(!current->mmap_tail) - buf=0x2000000; - else - buf=current->mmap_tail->endaddr; - } - //申请mmap - struct mmap_struct *mmap=(struct mmap_struct *)malloc(sizeof(struct mmap_struct)); - mmap->address=buf; - mmap->size=len; - mmap->endaddr=(unsigned long)buf+(len + 0xfff)&0xfffff000; - mmap->rw=prot; - mmap->ps=flags; - mmap->next=NULL; - //加入current->mmap - if(!current->mmap) - {current->mmap=current->mmap_tail=mmap;} - else - current->mmap_tail->next=mmap; - printk("buf: %x\n",(unsigned long )buf); - - //分配物理页 - - unsigned long from; - unsigned long to; - unsigned long from_page; - unsigned long to_page; - unsigned long phys_addr; - unsigned long tpage; - unsigned long address=mmap->address; - while(addressendaddr) - { - from_page = ((mmap->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 MAP_FAILED; - } - else - *(unsigned long *)from_page= tpage | 7; - 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 MAP_FAILED; - } - else - *(unsigned long *)from_page= tpage | 7; - *(unsigned long *)from_page &= (prot&PROT_WRITE); //分配读写权限 - if(flags & MAP_SHARED) - { - struct task_struct ** p; - - for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { - if (!*p) - continue; - if (current == *p) - continue; - if(!my_share(address,*p)) - printk("share failed at task:pid=%d",(*p)->pid); - } - } - address+=PAGE_SIZE; - } - - //read and put in - if (!(block = inode->i_zone[0])) - return NULL; - if (!(bh = bread(inode->i_dev,block))) - return NULL; - temp = (char *) bh->b_data; - p1=temp;p2=buf; - while(l--) - put_fs_byte(*(p1++),p2++); - printk("%s\n",temp); - return buf; -} -int sys_munmap() -{ - return -1; -} diff --git a/linux/kernel/system_call.s b/linux/kernel/system_call.s index d26f913..b0a7e70 100644 --- a/linux/kernel/system_call.s +++ b/linux/kernel/system_call.s @@ -227,9 +227,8 @@ sys_fork: pushl %edi pushl %ebp pushl %eax - pushl $0x0 #for flag call copy_process - addl $24,%esp #for flag + addl $20,%esp 1: ret .align 4 @@ -237,17 +236,13 @@ 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 + call copy_process_clone + addl $20,%esp 1: ret hd_interrupt: diff --git a/linux/mm/memory.c b/linux/mm/memory.c index e7f6a52..c6b672b 100644 --- a/linux/mm/memory.c +++ b/linux/mm/memory.c @@ -147,7 +147,7 @@ int free_page_tables(unsigned long from,unsigned long size) * 1 Mb-range, so the pages can be shared with the kernel. Thus the * special case for nr=xxxx. */ -int copy_page_tables(unsigned long from,unsigned long to,long size) +int copy_page_tables(unsigned long from,unsigned long to,long size ) { unsigned long * from_page_table; unsigned long * to_page_table; @@ -809,3 +809,160 @@ mytag: +/* + 直接让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-4 00 00 00 00 */ + /* child_stack-8 00 00 00 00 */ + /* child_stack-12 arg */ + /* child_stack-16 fn */ //esp + /* child_stack-20 00 00 00 00 */ + /* child_stack-24 00 00 00 00 */ + /* child_stack-28 00 00 00 00 */ + /* child_stack-32 0x000000c3 */ +/* +int do_clone(int nr,long tmp,int (*fn)(void *), void *child_stack, int flag) +{ + void * argv =NULL; + //共享物理页:写法有缺陷,可能child——stack跨页 + //子进程task[nr]的页表项获取,目的是更新成child——stacK的物理页 + unsigned long nrfrom_page,nrfrom,from_page,from,tpage,address; + address = task[nr]->tss.esp; + 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; + unsigned long stack[128]; + unsigned long off=(unsigned long)child_stack & 0xfff; + if(off < 32) + { + printk("地址跨页,我也没办法.\n"); + return -1; + } + + //更新esp,让其指向child_stack同样偏移的地点; + //注意:这里child_stack 指向的是高地址,要向下面push. + task[nr]->tss.esp &=0xfffff000; + task[nr]->tss.esp |=off - 16; + //eip 只有一条ret //所以传进来的fn必须以exit结尾,不能return , + //因为我不会return这个玩意push ebp 又pop 啥的 + task[nr]->tss.eip &=0xfffff000; + task[nr]->tss.eip |=off - 32; + //ret eip + + stack[0]=0x000000c3; + stack[4]=(unsigned long)fn; + stack[5]=(unsigned long)argv; + char * p1=stack, *p2=(unsigned long) child_stack - 32,len=32; + while(len--) + put_fs_byte(*(p1++),p2++); + printk("nr:%d::fn:%x\n",nr,(unsigned long )fn); + return 0; +} +*/ +int copy_page_tables_clone(unsigned long from,unsigned long to,long size ) +{ + unsigned long * from_page_table; + unsigned long * to_page_table; + unsigned long this_page; + unsigned long * from_dir, * to_dir; + unsigned long nr; + + if ((from&0x3fffff) || (to&0x3fffff)) + panic("copy_page_tables called with wrong alignment"); + 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)) + 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 */ + *to_dir = ((unsigned long) to_page_table) | 7; + nr = (from==0)?0xA0:1024; + for ( ; nr-- > 0 ; from_page_table++,to_page_table++) { + this_page = *from_page_table; + if (!(1 & this_page)) + continue; + *to_page_table = this_page; + if (this_page > LOW_MEM) { + *from_page_table = this_page; + this_page -= LOW_MEM; + this_page >>= 12; + mem_map[this_page]++; + } + } + } + invalidate(); + return 0; +} \ No newline at end of file