diff --git a/memory.c b/memory.c deleted file mode 100644 index ac98d55..0000000 --- a/memory.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * linux/mm/memory.c - * - * (C) 1991 Linus Torvalds - */ - -/* - * demand-loading started 01.12.91 - seems it is high on the list of - * things wanted, and it should be easy to implement. - Linus - */ - -/* - * Ok, demand-loading was easy, shared pages a little bit tricker. Shared - * pages started 02.12.91, seems to work. - Linus. - * - * Tested sharing by executing about 30 /bin/sh: under the old kernel it - * would have taken more than the 6M I have free, but it worked well as - * far as I could see. - * - * Also corrected some "invalidate()"s - I wasn't doing enough of them. - */ - -#include - -#include - -#include -#include -#include - -volatile void do_exit(long code); - -static inline volatile void oom(void) -{ - printk("out of memory\n\r"); - do_exit(SIGSEGV); -} - -#define invalidate() \ -__asm__("movl %%eax,%%cr3"::"a" (0)) - -/* these are not to be changed without changing head.s etc */ -#define LOW_MEM 0x100000 -#define PAGING_MEMORY (15*1024*1024) -#define PAGING_PAGES (PAGING_MEMORY>>12) -#define MAP_NR(addr) (((addr)-LOW_MEM)>>12) -#define USED 100 - -#define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \ -current->start_code + current->end_code) - -static long HIGH_MEMORY = 0; - -#define copy_page(from,to) \ -__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024)) - -static unsigned char mem_map [ PAGING_PAGES ] = {0,}; - -/* - * Get physical address of first (actually last :-) free page, and mark it - * used. If no free pages left, return 0. - */ -unsigned long get_free_page(void) -{ -register unsigned long __res asm("ax"); - -__asm__("std ; repne ; scasb\n\t" - "jne 1f\n\t" - "movb $1,1(%%edi)\n\t" - "sall $12,%%ecx\n\t" - "addl %2,%%ecx\n\t" - "movl %%ecx,%%edx\n\t" - "movl $1024,%%ecx\n\t" - "leal 4092(%%edx),%%edi\n\t" - "rep ; stosl\n\t" - "movl %%edx,%%eax\n\t" - "1:" - "cld\n\t" /* by wyj */ - :"=a" (__res) - :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), - "D" (mem_map+PAGING_PAGES-1) - ); -return __res; -} - -/* - * Free a page of memory at physical address 'addr'. Used by - * 'free_page_tables()' - */ -void free_page(unsigned long addr) -{ - if (addr < LOW_MEM) return; - if (addr >= HIGH_MEMORY) - panic("trying to free nonexistent page"); - addr -= LOW_MEM; - addr >>= 12; - if (mem_map[addr]--) return; - mem_map[addr]=0; - panic("trying to free free page"); -} - -/* - * This function frees a continuos block of page tables, as needed - * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks. - */ -int free_page_tables(unsigned long from,unsigned long size) -{ - unsigned long *pg_table; - unsigned long * dir, nr; - - if (from & 0x3fffff) - panic("free_page_tables called with wrong alignment"); - if (!from) - panic("Trying to free up swapper memory space"); - size = (size + 0x3fffff) >> 22; - dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */ - for ( ; size-->0 ; dir++) { - if (!(1 & *dir)) - continue; - pg_table = (unsigned long *) (0xfffff000 & *dir); - for (nr=0 ; nr<1024 ; nr++) { - if (1 & *pg_table) - free_page(0xfffff000 & *pg_table); - *pg_table = 0; - pg_table++; - } - free_page(0xfffff000 & *dir); - *dir = 0; - } - invalidate(); - return 0; -} - -/* - * 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. - */ -int copy_page_tables(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; - this_page &= ~2; - *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; -} - -/* - * 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.) - */ -unsigned long put_page(unsigned long page,unsigned long address) -{ - unsigned long tmp, *page_table; - -/* NOTE !!! This uses the fact that _pg_dir=0 */ - - 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) - printk("mem_map disagrees with %p at %p\n",page,address); - page_table = (unsigned long *) ((address>>20) & 0xffc); - if ((*page_table)&1) - page_table = (unsigned long *) (0xfffff000 & *page_table); - else { - if (!(tmp=get_free_page())) - return 0; - *page_table = tmp|7; - page_table = (unsigned long *) tmp; - } - page_table[(address>>12) & 0x3ff] = page | 7; -/* no need for invalidate */ - return page; -} - -void un_wp_page(unsigned long * table_entry) -{ - unsigned long old_page,new_page; - - old_page = 0xfffff000 & *table_entry; - if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) { - *table_entry |= 2; - invalidate(); - return; - } - if (!(new_page=get_free_page())) - oom(); - if (old_page >= LOW_MEM) - mem_map[MAP_NR(old_page)]--; - *table_entry = new_page | 7; - invalidate(); - copy_page(old_page,new_page); -} - -/* - * This routine handles present pages, when users try to write - * to a shared page. It is done by copying the page to a new address - * and decrementing the shared-page counter for the old page. - * - * If it's in code space we exit with a segment error. - */ -void do_wp_page(unsigned long error_code,unsigned long address) -{ -#if 0 -/* we cannot do this yet: the estdio library writes to code space */ -/* stupid, stupid. I really want the libc.a from GNU */ - if (CODE_SPACE(address)) - do_exit(SIGSEGV); -#endif - un_wp_page((unsigned long *) - (((address>>10) & 0xffc) + (0xfffff000 & - *((unsigned long *) ((address>>20) &0xffc))))); - -} - -void write_verify(unsigned long address) -{ - unsigned long page; - - if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1)) - return; - page &= 0xfffff000; - page += ((address>>10) & 0xffc); - if ((3 & *(unsigned long *) page) == 1) /* non-writeable, present */ - un_wp_page((unsigned long *) page); - return; -} - -void get_empty_page(unsigned long address) -{ - unsigned long tmp; - - if (!(tmp=get_free_page()) || !put_page(tmp,address)) { - free_page(tmp); /* 0 is ok - ignored */ - oom(); - } -} - -/* - * try_to_share() checks the page at address "address" in the task "p", - * to see if it exists, and if it is clean. If so, share it with the current - * task. - * - * NOTE! This assumes we have checked that p != current, and that they - * share the same executable. - */ -static int try_to_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 += ((p->start_code>>20) & 0xffc); - to_page += ((current->start_code>>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? */ - if ((phys_addr & 0x41) != 0x01) - return 0; - phys_addr &= 0xfffff000; - if (phys_addr >= HIGH_MEMORY || phys_addr < LOW_MEM) - return 0; - to = *(unsigned long *) to_page; - if (!(to & 1)) - if (to = get_free_page()) - *(unsigned long *) to_page = to | 7; - else - oom(); - to &= 0xfffff000; - to_page = to + ((address>>10) & 0xffc); - if (1 & *(unsigned long *) to_page) - panic("try_to_share: to_page already exists"); -/* share them: write-protect */ - *(unsigned long *) from_page &= ~2; - *(unsigned long *) to_page = *(unsigned long *) from_page; - invalidate(); - phys_addr -= LOW_MEM; - phys_addr >>= 12; - mem_map[phys_addr]++; - return 1; -} - -/* - * share_page() tries to find a process that could share a page with - * the current one. Address is the address of the wanted page relative - * to the current data space. - * - * We first check if it is at all feasible by checking executable->i_count. - * It should be >1 if there are other tasks sharing this inode. - */ -static int share_page(unsigned long address) -{ - struct task_struct ** p; - - if (!current->executable) - return 0; - if (current->executable->i_count < 2) - return 0; - for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { - if (!*p) - continue; - if (current == *p) - continue; - if ((*p)->executable != current->executable) - continue; - if (try_to_share(address,*p)) - return 1; - } - return 0; -} - -/* -do_no_page()是页异常中断过程中调用的缺页处理函数。它首先判断指定的线性地址在一个进程空 -间中相对于进程基址的偏移长度值。如果它大于代码加数据长度,或者进程刚开始创建,则立刻申请一 -页物理内存,并映射到进程线性地址中,然后返回;接着尝试进行页面共享操作,若成功,则立刻返回; -否则申请一页内存并从设备中读入一页信息;若加入该页信息时,指定线性地址+1 页长度超过了进程代 -码加数据的长度,则将超过的部分清零。然后将该页映射到指定的线性地址处。 -*/ - -void do_no_page(unsigned long error_code,unsigned long address) -{ - int nr[4]; - unsigned long tmp; - unsigned long page; - int block,i; - - address &= 0xfffff000; // address 处缺页页面地址。 - tmp = address - current->start_code; // 缺页页面对应逻辑地址。 - if (!current->executable || tmp >= current->end_data) { - get_empty_page(address); - return; - } - if (share_page(tmp)) // 尝试逻辑地址 tmp 处页面的共享。 - return; - if (!(page = get_free_page())) // 申请一页物理内存 - oom(); -/* 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); - bread_page(page,current->executable->i_dev,nr); - i = tmp + 4096 - current->end_data; - tmp = page + 4096; - while (i-- > 0) { - tmp--; - *(char *)tmp = 0; - } - if (put_page(page,address)) - return; - free_page(page); - oom(); -} - -/* for exec.c/do_execve2 */ -/* coded by dj */ -void my_do_no_page(unsigned long address) -{ - int nr[4]; - unsigned long tmp; - unsigned long page; - int block,i; - - address &= 0xfffff000; // address 处缺页页面地址。 - tmp = address - current->start_code; // 缺页页面对应逻辑地址。 - - /*  - 若当前进程的executable 空,或者指定地址超出代码+数据长度,则申请一页物理 - 内存,并映射到指定的线性地址处。executable 是进程的i 节点结构。该值为0,表明 - 进程刚开始设置,需要内存;而指定的线性地址超出代码加数据长度,表明进程在申请新 - 的内存空间,也需要给予。因此就直接调用get_empty_page()函数,申请一页物理内存 - 并映射到指定线性地址处即可。 - */ - - if (!current->executable || tmp >= current->end_data) { - get_empty_page(address); - return; - } - if (share_page(tmp)) // 尝试逻辑地址 tmp 处页面的共享。 - return; - if (!(page = get_free_page())) // 申请一页物理内存 - oom(); -/* remember that 1 block is used for header */ - -/* 记住,(程序)头要使用 1 个数据块 */ - // 根据这个块号和执行文件的 i 节点,我们就可以从映射位图中找到对应块设备中对应的设备 - // 逻辑块号(保存在 nr[]数组中)。利用 bread_page()即可把这 4 个逻辑块读入到物理页面 - // page 中。 - block = 1 + tmp/BLOCK_SIZE; - for (i=0 ; i<4 ; block++,i++) - nr[i] = bmap(current->executable,block); - bread_page(page,current->executable->i_dev,nr); - i = tmp + 4096 - current->end_data; // 超出的字节长度值。 - tmp = page + 4096; // tmp 指向页面末端。 - while (i-- > 0) { // 页面末端 i 字节清零。 - tmp--; - *(char *)tmp = 0; - } - - // 最后把引起缺页异常的一页物理页面映射到指定线性地址 address 处。若操作成功就返回, - // 否则就释放内存页,显示内存不够。 - if (put_page(page,address)) - return; - free_page(page); - oom(); -} - -void mem_init(long start_mem, long end_mem) -{ - int i; - - HIGH_MEMORY = end_mem; - for (i=0 ; i>= 12; - while (end_mem-->0) - mem_map[i++]=0; -} - -void calc_mem(void) -{ - int i,j,k,free=0; - long * pg_tbl; - - for(i=0 ; i