Annotation of linux/mm/memory.c, revision 1.1

1.1     ! root        1: #include <signal.h>
        !             2: 
        !             3: #include <linux/config.h>
        !             4: #include <linux/head.h>
        !             5: #include <linux/kernel.h>
        !             6: #include <asm/system.h>
        !             7: 
        !             8: int do_exit(long code);
        !             9: 
        !            10: #define invalidate() \
        !            11: __asm__("movl %%eax,%%cr3"::"a" (0))
        !            12: 
        !            13: #if (BUFFER_END < 0x100000)
        !            14: #define LOW_MEM 0x100000
        !            15: #else
        !            16: #define LOW_MEM BUFFER_END
        !            17: #endif
        !            18: 
        !            19: /* these are not to be changed - thay are calculated from the above */
        !            20: #define PAGING_MEMORY (HIGH_MEMORY - LOW_MEM)
        !            21: #define PAGING_PAGES (PAGING_MEMORY/4096)
        !            22: #define MAP_NR(addr) (((addr)-LOW_MEM)>>12)
        !            23: 
        !            24: #if (PAGING_PAGES < 10)
        !            25: #error "Won't work"
        !            26: #endif
        !            27: 
        !            28: #define copy_page(from,to) \
        !            29: __asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
        !            30: 
        !            31: static unsigned short mem_map [ PAGING_PAGES ] = {0,};
        !            32: 
        !            33: /*
        !            34:  * Get physical address of first (actually last :-) free page, and mark it
        !            35:  * used. If no free pages left, return 0.
        !            36:  */
        !            37: unsigned long get_free_page(void)
        !            38: {
        !            39: register unsigned long __res asm("ax");
        !            40: 
        !            41: __asm__("std ; repne ; scasw\n\t"
        !            42:        "jne 1f\n\t"
        !            43:        "movw $1,2(%%edi)\n\t"
        !            44:        "sall $12,%%ecx\n\t"
        !            45:        "movl %%ecx,%%edx\n\t"
        !            46:        "addl %2,%%edx\n\t"
        !            47:        "movl $1024,%%ecx\n\t"
        !            48:        "leal 4092(%%edx),%%edi\n\t"
        !            49:        "rep ; stosl\n\t"
        !            50:        "movl %%edx,%%eax\n"
        !            51:        "1:"
        !            52:        :"=a" (__res)
        !            53:        :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),
        !            54:        "D" (mem_map+PAGING_PAGES-1)
        !            55:        :"di","cx","dx");
        !            56: return __res;
        !            57: }
        !            58: 
        !            59: /*
        !            60:  * Free a page of memory at physical address 'addr'. Used by
        !            61:  * 'free_page_tables()'
        !            62:  */
        !            63: void free_page(unsigned long addr)
        !            64: {
        !            65:        if (addr<LOW_MEM) return;
        !            66:        if (addr>HIGH_MEMORY)
        !            67:                panic("trying to free nonexistent page");
        !            68:        addr -= LOW_MEM;
        !            69:        addr >>= 12;
        !            70:        if (mem_map[addr]--) return;
        !            71:        mem_map[addr]=0;
        !            72:        panic("trying to free free page");
        !            73: }
        !            74: 
        !            75: /*
        !            76:  * This function frees a continuos block of page tables, as needed
        !            77:  * by 'exit()'. As does copy_page_tables(), this handles only 4Mb blocks.
        !            78:  */
        !            79: int free_page_tables(unsigned long from,unsigned long size)
        !            80: {
        !            81:        unsigned long *pg_table;
        !            82:        unsigned long * dir, nr;
        !            83: 
        !            84:        if (from & 0x3fffff)
        !            85:                panic("free_page_tables called with wrong alignment");
        !            86:        if (!from)
        !            87:                panic("Trying to free up swapper memory space");
        !            88:        size = (size + 0x3fffff) >> 22;
        !            89:        dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
        !            90:        for ( ; size-->0 ; dir++) {
        !            91:                if (!(1 & *dir))
        !            92:                        continue;
        !            93:                pg_table = (unsigned long *) (0xfffff000 & *dir);
        !            94:                for (nr=0 ; nr<1024 ; nr++) {
        !            95:                        if (1 & *pg_table)
        !            96:                                free_page(0xfffff000 & *pg_table);
        !            97:                        *pg_table = 0;
        !            98:                        pg_table++;
        !            99:                }
        !           100:                free_page(0xfffff000 & *dir);
        !           101:                *dir = 0;
        !           102:        }
        !           103:        invalidate();
        !           104:        return 0;
        !           105: }
        !           106: 
        !           107: /*
        !           108:  *  Well, here is one of the most complicated functions in mm. It
        !           109:  * copies a range of linerar addresses by copying only the pages.
        !           110:  * Let's hope this is bug-free, 'cause this one I don't want to debug :-)
        !           111:  *
        !           112:  * Note! We don't copy just any chunks of memory - addresses have to
        !           113:  * be divisible by 4Mb (one page-directory entry), as this makes the
        !           114:  * function easier. It's used only by fork anyway.
        !           115:  *
        !           116:  * NOTE 2!! When from==0 we are copying kernel space for the first
        !           117:  * fork(). Then we DONT want to copy a full page-directory entry, as
        !           118:  * that would lead to some serious memory waste - we just copy the
        !           119:  * first 160 pages - 640kB. Even that is more than we need, but it
        !           120:  * doesn't take any more memory - we don't copy-on-write in the low
        !           121:  * 1 Mb-range, so the pages can be shared with the kernel. Thus the
        !           122:  * special case for nr=xxxx.
        !           123:  */
        !           124: int copy_page_tables(unsigned long from,unsigned long to,long size)
        !           125: {
        !           126:        unsigned long * from_page_table;
        !           127:        unsigned long * to_page_table;
        !           128:        unsigned long this_page;
        !           129:        unsigned long * from_dir, * to_dir;
        !           130:        unsigned long nr;
        !           131: 
        !           132:        if ((from&0x3fffff) || (to&0x3fffff))
        !           133:                panic("copy_page_tables called with wrong alignment");
        !           134:        from_dir = (unsigned long *) ((from>>20) & 0xffc); /* _pg_dir = 0 */
        !           135:        to_dir = (unsigned long *) ((to>>20) & 0xffc);
        !           136:        size = ((unsigned) (size+0x3fffff)) >> 22;
        !           137:        for( ; size-->0 ; from_dir++,to_dir++) {
        !           138:                if (1 & *to_dir)
        !           139:                        panic("copy_page_tables: already exist");
        !           140:                if (!(1 & *from_dir))
        !           141:                        continue;
        !           142:                from_page_table = (unsigned long *) (0xfffff000 & *from_dir);
        !           143:                if (!(to_page_table = (unsigned long *) get_free_page()))
        !           144:                        return -1;      /* Out of memory, see freeing */
        !           145:                *to_dir = ((unsigned long) to_page_table) | 7;
        !           146:                nr = (from==0)?0xA0:1024;
        !           147:                for ( ; nr-- > 0 ; from_page_table++,to_page_table++) {
        !           148:                        this_page = *from_page_table;
        !           149:                        if (!(1 & this_page))
        !           150:                                continue;
        !           151:                        this_page &= ~2;
        !           152:                        *to_page_table = this_page;
        !           153:                        if (this_page > LOW_MEM) {
        !           154:                                *from_page_table = this_page;
        !           155:                                this_page -= LOW_MEM;
        !           156:                                this_page >>= 12;
        !           157:                                mem_map[this_page]++;
        !           158:                        }
        !           159:                }
        !           160:        }
        !           161:        invalidate();
        !           162:        return 0;
        !           163: }
        !           164: 
        !           165: /*
        !           166:  * This function puts a page in memory at the wanted address.
        !           167:  * It returns the physical address of the page gotten, 0 if
        !           168:  * out of memory (either when trying to access page-table or
        !           169:  * page.)
        !           170:  */
        !           171: unsigned long put_page(unsigned long page,unsigned long address)
        !           172: {
        !           173:        unsigned long tmp, *page_table;
        !           174: 
        !           175: /* NOTE !!! This uses the fact that _pg_dir=0 */
        !           176: 
        !           177:        if (page < LOW_MEM || page > HIGH_MEMORY)
        !           178:                printk("Trying to put page %p at %p\n",page,address);
        !           179:        if (mem_map[(page-LOW_MEM)>>12] != 1)
        !           180:                printk("mem_map disagrees with %p at %p\n",page,address);
        !           181:        page_table = (unsigned long *) ((address>>20) & 0xffc);
        !           182:        if ((*page_table)&1)
        !           183:                page_table = (unsigned long *) (0xfffff000 & *page_table);
        !           184:        else {
        !           185:                if (!(tmp=get_free_page()))
        !           186:                        return 0;
        !           187:                *page_table = tmp|7;
        !           188:                page_table = (unsigned long *) tmp;
        !           189:        }
        !           190:        page_table[(address>>12) & 0x3ff] = page | 7;
        !           191:        return page;
        !           192: }
        !           193: 
        !           194: void un_wp_page(unsigned long * table_entry)
        !           195: {
        !           196:        unsigned long old_page,new_page;
        !           197: 
        !           198:        old_page = 0xfffff000 & *table_entry;
        !           199:        if (old_page >= LOW_MEM && mem_map[MAP_NR(old_page)]==1) {
        !           200:                *table_entry |= 2;
        !           201:                return;
        !           202:        }
        !           203:        if (!(new_page=get_free_page()))
        !           204:                do_exit(SIGSEGV);
        !           205:        if (old_page >= LOW_MEM)
        !           206:                mem_map[MAP_NR(old_page)]--;
        !           207:        *table_entry = new_page | 7;
        !           208:        copy_page(old_page,new_page);
        !           209: }      
        !           210: 
        !           211: /*
        !           212:  * This routine handles present pages, when users try to write
        !           213:  * to a shared page. It is done by copying the page to a new address
        !           214:  * and decrementing the shared-page counter for the old page.
        !           215:  */
        !           216: void do_wp_page(unsigned long error_code,unsigned long address)
        !           217: {
        !           218:        un_wp_page((unsigned long *)
        !           219:                (((address>>10) & 0xffc) + (0xfffff000 &
        !           220:                *((unsigned long *) ((address>>20) &0xffc)))));
        !           221: 
        !           222: }
        !           223: 
        !           224: void write_verify(unsigned long address)
        !           225: {
        !           226:        unsigned long page;
        !           227: 
        !           228:        if (!( (page = *((unsigned long *) ((address>>20) & 0xffc)) )&1))
        !           229:                return;
        !           230:        page &= 0xfffff000;
        !           231:        page += ((address>>10) & 0xffc);
        !           232:        if ((3 & *(unsigned long *) page) == 1)  /* non-writeable, present */
        !           233:                un_wp_page((unsigned long *) page);
        !           234:        return;
        !           235: }
        !           236: 
        !           237: void do_no_page(unsigned long error_code,unsigned long address)
        !           238: {
        !           239:        unsigned long tmp;
        !           240: 
        !           241:        if (tmp=get_free_page())
        !           242:                if (put_page(tmp,address))
        !           243:                        return;
        !           244:        do_exit(SIGSEGV);
        !           245: }
        !           246: 
        !           247: void calc_mem(void)
        !           248: {
        !           249:        int i,j,k,free=0;
        !           250:        long * pg_tbl;
        !           251: 
        !           252:        for(i=0 ; i<PAGING_PAGES ; i++)
        !           253:                if (!mem_map[i]) free++;
        !           254:        printk("%d pages free (of %d)\n\r",free,PAGING_PAGES);
        !           255:        for(i=2 ; i<1024 ; i++) {
        !           256:                if (1&pg_dir[i]) {
        !           257:                        pg_tbl=(long *) (0xfffff000 & pg_dir[i]);
        !           258:                        for(j=k=0 ; j<1024 ; j++)
        !           259:                                if (pg_tbl[j]&1)
        !           260:                                        k++;
        !           261:                        printk("Pg-dir[%d] uses %d pages\n",i,k);
        !           262:                }
        !           263:        }
        !           264: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.