diff --git a/linux/mm/memory.c b/linux/mm/memory.c index 0fdf229..80b36c7 100644 --- a/linux/mm/memory.c +++ b/linux/mm/memory.c @@ -19,13 +19,14 @@ * * Also corrected some "invalidate()"s - I wasn't doing enough of them. */ - +#include #include #include #include #include #include - +#include +#include volatile void do_exit(long code); static inline volatile void oom(void) @@ -369,8 +370,8 @@ void do_no_page(unsigned long error_code,unsigned long address) unsigned long page; int block,i; - if (current->pid > 5) - printk(" --do_no_page: address=%x, pid=%d\n", address, current->pid); + /* if (current->pid > 5) + printk(" --do_no_page: address=%x, pid=%d\n", address, current->pid); */ address &= 0xfffff000; tmp = address - current->start_code; @@ -466,3 +467,375 @@ void calc_mem(void) } +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( (flags & MAP_SHARED)&& (flags &MAP_PRIVATE )) + { + printk("error with private and shared request.\n"); + return -1; + } + if(len<=0 || off<0 || (off%PAGE_SIZE)) + { + if(len<=0) + printk("the len of the wanting bytes must be positive.\n"); + else + printk("offset must be the mul of 4096.\n"); + 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->filenode=(struct m_inode*)malloc(sizeof(struct m_inode)); + memcpy(mmap->filenode,inode,sizeof(struct m_inode)); + printk("izone[0]:%x:\n",inode->i_zone[0]); + if(!mmap->filenode->i_count)mmap->filenode->i_count=1; + mmap->off=off; + mmap->next=NULL; + //加入current->mmap + if(!current->mmap) + {current->mmap=current->mmap_tail=mmap;} + else { + current->mmap_tail->next=mmap; + current->mmap_tail=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 = ((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; + 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 MAP_FAILED; + } + else + { + *(unsigned long *)from_page= tpage | 7; + mem_map[(tpage-LOW_MEM)>>12]++; + } + *(unsigned long *)from_page &= (prot&PROT_WRITE); //分配读写权限 + + if(flags & MAP_SHARED) + { + printk("i am doing sharing."); + struct task_struct ** p; + + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p) + continue; + if (current == *p) + continue; + //在这一部分,我将current->address处的物理页复制给 + //所有进程的该区域,可能导致错误,但我们忽略。 + 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+off;p2=buf; + while(l--) + put_fs_byte(*(p1++),p2++); + printk("%s\n",temp+off); + return buf; +} +static int my_sync(off_t pos, struct m_inode * inode, char * buf, int count) +{ + int block,c; + struct buffer_head * bh; + char * p; + int i=0; + + //int block; + //struct buffer_head * bh; + struct dir_entry * de; + int ttp=0;; + printk("sync:izone[0]:%x:\n",inode->i_zone[0]); + if (!(block = inode->i_zone[0])) + return -1; + if (!(bh = bread(inode->i_dev,block))) + return -1; + de=(char*)bh->b_data; + for(ttp=0;ttpi_dev,block))) + break; + c = pos % BLOCK_SIZE; + p = c + bh->b_data; + bh->b_dirt = 1; + c = BLOCK_SIZE-c; + if (c > count-i) c = count-i; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + i += c; + while (c-->0) + *(p++) = get_fs_byte(buf++); + brelse(bh); + } + inode->i_mtime = CURRENT_TIME;//文件最后修改时间 + inode->i_ctime = CURRENT_TIME;//i节点修改时间 + return (i?i:-1); +} + + +int sys_munmap(void * start ,size_t size) +{ + struct mmap_struct *temp=current->mmap; + struct mmap_struct *pre=NULL; + while(temp!=NULL) + { + if(temp->address==(unsigned long)start) + break; + else temp=temp->next; + pre=temp; + } + if(!temp) + { + printk("invalid address.\n"); + return -1; + } + if(!pre) + { + if(current->mmap_tail==current->mmap)current->mmap_tail=NULL; + current->mmap==current->mmap->next; + } + if(temp->next=NULL) + { + current->mmap_tail=pre; + pre->next=NULL; + } + else{ + pre->next=temp->next; + } + printk("addr: %lx,endaddr : %lx\n",temp->address,temp->endaddr); + unsigned long from; + unsigned long to; + unsigned long from_page; + unsigned long to_page; + unsigned long phys_addr; + unsigned long tpage; + unsigned long address=temp->address; + if(!(temp->ps & MAP_SHARED)) + goto mytag; + //若为共享,执行下面的代码 + while (address < temp ->endaddr) + { + printk("addr: %lx\n",address); + from_page = ((address>>20) & 0xffc); + from_page += ((current->start_code>>20) & 0xffc);//页目录 + from=*(unsigned long *)from_page; //页表项 + from &= 0xfffff000; + from_page = from + ((address>>10) & 0xffc); + phys_addr = (*(unsigned long *)from_page & 0xfffff000); + //printk("addr: %lx",*(unsigned long *)from_page); + if(!(*(unsigned long *)from_page & 1)) + { + printk("error of deleting page."); + return -1; + } + if(temp->ps & MAP_SHARED) + { + struct task_struct ** p; + + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p) + continue; + if (current == *p) + continue; + to_page = ((address>>20) & 0xffc)+(((*p)->start_code>>20) & 0xffc); + to = *(unsigned long *) to_page; + if(!(to & 1)) + continue; + to &= 0xfffff000; + to_page = to + ((address>>10) & 0xffc); + if(!(*(unsigned long *)to_page &1)) + continue; + to = (*(unsigned long *)to_page & 0xfffff000); + if(phys_addr == to) + { + *(unsigned long *)to_page &= ~1; + mem_map[(phys_addr-LOW_MEM)>>12]--; + } + } + } + address+=PAGE_SIZE; + } + if(temp->ps & MAP_SHARED) + { + if(my_sync(temp->off,temp->filenode,(char*)(temp->address),temp->size)==-1) + return -1; + } +mytag: + //取消物理页写权限 + while (address < temp ->endaddr) + { + from_page = ((address>>20) & 0xffc); + from_page += ((current->start_code>>20) & 0xffc);//页目录 + from=*(unsigned long *)from_page; //页表项 + from &= 0xfffff000; + from_page = from + ((address>>10) & 0xffc); + phys_addr = (*(unsigned long *)from_page & 0xfffff000); + //printk("addr: %lx",*(unsigned long *)from_page); + if(!(*(unsigned long *)from_page & 1)) + { + printk("error of deleting page."); + return -1; + } + else{ + *(unsigned long *)from_page &= ~1; + } + } + int block; + struct buffer_head * bh; + struct dir_entry * de; + int ttp=0;; + printk("temp->izone[0]:%x:\n",temp->filenode->i_zone[0]); + if (!(block = temp->filenode->i_zone[0])) + return -1; + if (!(bh = bread(temp->filenode->i_dev,block))) + return -1; + de=(char*)bh->b_data; + for(ttp=0;ttpsize;ttp++) + { + printk("char:%c,",*(de+ttp)); + } + free(temp); + return 0; +} + + +